femagtools 1.7.4__py3-none-any.whl → 1.7.6__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 +4 -1
- femagtools/dxfsl/area.py +109 -7
- femagtools/dxfsl/conv.py +15 -0
- femagtools/dxfsl/converter.py +30 -15
- femagtools/dxfsl/fslrenderer.py +3 -0
- femagtools/dxfsl/geom.py +128 -18
- femagtools/dxfsl/machine.py +26 -9
- femagtools/fsl.py +4 -1
- femagtools/machine/pm.py +191 -43
- femagtools/machine/utils.py +2 -2
- femagtools/plot/bch.py +19 -5
- femagtools/templates/mesh-airgap.mako +9 -0
- femagtools/templates/statorRotor3.mako +3 -0
- {femagtools-1.7.4.dist-info → femagtools-1.7.6.dist-info}/METADATA +1 -1
- {femagtools-1.7.4.dist-info → femagtools-1.7.6.dist-info}/RECORD +20 -20
- {femagtools-1.7.4.dist-info → femagtools-1.7.6.dist-info}/WHEEL +1 -1
- {femagtools-1.7.4.dist-info → femagtools-1.7.6.dist-info}/LICENSE +0 -0
- {femagtools-1.7.4.dist-info → femagtools-1.7.6.dist-info}/entry_points.txt +0 -0
- {femagtools-1.7.4.dist-info → femagtools-1.7.6.dist-info}/top_level.txt +0 -0
femagtools/__init__.py
CHANGED
femagtools/bch.py
CHANGED
@@ -613,6 +613,7 @@ class Reader:
|
|
613
613
|
|
614
614
|
def __read_general_machine_data(self, content):
|
615
615
|
mcfiles = []
|
616
|
+
slotsides = 1
|
616
617
|
for l in content:
|
617
618
|
try:
|
618
619
|
if l.find('Armature Length') > -1:
|
@@ -631,8 +632,10 @@ class Reader:
|
|
631
632
|
self.machine['p_sim'] = int(l.split()[-1])
|
632
633
|
elif l.find('Total Number of Slots') > -1:
|
633
634
|
self.machine['Q'] = int(l.split()[-1])
|
635
|
+
elif l.find('Total Number of Slot-Sides') > -1:
|
636
|
+
slotsides = int(l.split()[-1])
|
634
637
|
elif l.find('Number of Slot-Sides sim.') > -1:
|
635
|
-
self.machine['qs_sim'] = int(l.split()[-1])
|
638
|
+
self.machine['qs_sim'] = int(l.split()[-1])*self.machine['Q']//slotsides
|
636
639
|
elif l.find('POC-File used in calculation') > -1:
|
637
640
|
self.machine['pocfile'] = l.split(
|
638
641
|
':')[-1].strip().replace('\\', '\\\\')
|
femagtools/dxfsl/area.py
CHANGED
@@ -40,6 +40,8 @@ TYPE_MAGNET_OR_IRON = 9
|
|
40
40
|
TYPE_SHAFT = 10
|
41
41
|
TYPE_MAGNET_RECT_NEAR_AIRGAP = 11
|
42
42
|
TYPE_WINDINGS_OR_AIR = 12
|
43
|
+
TYPE_WINDINGS_OR_IRON = 13
|
44
|
+
TYPE_FD_WINDINGS = 15
|
43
45
|
TYPE_MAGNET_UNDEFINED = 99
|
44
46
|
TYPE_GROUP = 20
|
45
47
|
|
@@ -84,6 +86,7 @@ class Area(object):
|
|
84
86
|
self.is_child = False
|
85
87
|
self.areas_inside = {}
|
86
88
|
self.areas_of_group = []
|
89
|
+
self.group_is_inside = False
|
87
90
|
|
88
91
|
def identifier(self):
|
89
92
|
return "{}-{}".format(self.id, self.type)
|
@@ -205,6 +208,8 @@ class Area(object):
|
|
205
208
|
return 'Iron'
|
206
209
|
if self.type == TYPE_WINDINGS:
|
207
210
|
return 'Windings'
|
211
|
+
if self.type == TYPE_FD_WINDINGS:
|
212
|
+
return 'Field Windings'
|
208
213
|
if self.type == TYPE_MAGNET_AIRGAP or self.type == TYPE_MAGNET_RECT:
|
209
214
|
return 'Magnet'
|
210
215
|
if self.type == TYPE_YOKE:
|
@@ -220,6 +225,8 @@ class Area(object):
|
|
220
225
|
return 'Iron'
|
221
226
|
if self.type == TYPE_WINDINGS:
|
222
227
|
return 'Wndg'
|
228
|
+
if self.type == TYPE_FD_WINDINGS:
|
229
|
+
return 'FD_Wndg'
|
223
230
|
if self.type == TYPE_MAGNET_AIRGAP or self.type == TYPE_MAGNET_RECT:
|
224
231
|
return 'Mag'
|
225
232
|
if self.type == TYPE_YOKE:
|
@@ -235,6 +242,8 @@ class Area(object):
|
|
235
242
|
return 'cyan'
|
236
243
|
if self.type == TYPE_WINDINGS:
|
237
244
|
return 'green'
|
245
|
+
if self.type == TYPE_FD_WINDINGS:
|
246
|
+
return 'yellow'
|
238
247
|
if self.type == TYPE_MAGNET_AIRGAP or self.type == TYPE_MAGNET_RECT:
|
239
248
|
return 'red'
|
240
249
|
if self.type == TYPE_YOKE:
|
@@ -250,6 +259,8 @@ class Area(object):
|
|
250
259
|
return 0.3
|
251
260
|
if self.type == TYPE_WINDINGS:
|
252
261
|
return 1.0
|
262
|
+
if self.type == TYPE_FD_WINDINGS:
|
263
|
+
return 1.0
|
253
264
|
if self.type == TYPE_MAGNET_AIRGAP or self.type == TYPE_MAGNET_RECT:
|
254
265
|
return 1.0
|
255
266
|
if self.type == TYPE_YOKE:
|
@@ -276,7 +287,9 @@ class Area(object):
|
|
276
287
|
return self.type == TYPE_IRON
|
277
288
|
|
278
289
|
def is_winding(self):
|
279
|
-
return
|
290
|
+
return \
|
291
|
+
self.type == TYPE_WINDINGS or \
|
292
|
+
self.type == TYPE_FD_WINDINGS
|
280
293
|
|
281
294
|
def is_magnet(self):
|
282
295
|
return self.type == TYPE_MAGNET_AIRGAP or self.type == TYPE_MAGNET_RECT
|
@@ -323,6 +336,17 @@ class Area(object):
|
|
323
336
|
return True
|
324
337
|
return False
|
325
338
|
|
339
|
+
def minmax_dist_from_center(self, center):
|
340
|
+
rmin = 1e20
|
341
|
+
rmax = 0
|
342
|
+
for n in self.list_of_nodes():
|
343
|
+
r = np.linalg.norm(np.array(n)-center)
|
344
|
+
if r < rmin:
|
345
|
+
rmin = r
|
346
|
+
if r > rmax:
|
347
|
+
rmax = r
|
348
|
+
return rmin, rmax
|
349
|
+
|
326
350
|
def minmax_angle_dist_from_center(self, center, dist):
|
327
351
|
circ = Circle(Element(center=center, radius=dist))
|
328
352
|
s = self.area[0]
|
@@ -1314,11 +1338,89 @@ class Area(object):
|
|
1314
1338
|
logger.debug("***** air #4\n")
|
1315
1339
|
return 0
|
1316
1340
|
|
1317
|
-
def
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1341
|
+
def mark_EESM_rotor_subregions(self,
|
1342
|
+
is_inner,
|
1343
|
+
mirrored,
|
1344
|
+
alpha,
|
1345
|
+
center,
|
1346
|
+
r_in,
|
1347
|
+
r_out,
|
1348
|
+
startangle,
|
1349
|
+
endangle):
|
1350
|
+
logger.debug("mark_EESM_rotor_subregions")
|
1351
|
+
|
1352
|
+
alpha = round(alpha, 6)
|
1353
|
+
|
1354
|
+
if self.is_circle():
|
1355
|
+
self.type = TYPE_AIR # air
|
1356
|
+
logger.debug(">>> air is a circle")
|
1357
|
+
return self.type
|
1358
|
+
|
1359
|
+
if is_inner:
|
1360
|
+
self.close_to_ag = np.isclose(r_out, self.max_dist, rtol=1e-9, atol=0.005)
|
1361
|
+
close_to_opposition = greater_equal(r_in * 1.05, self.min_dist)
|
1362
|
+
airgap_radius = r_out
|
1363
|
+
opposite_radius = r_in
|
1364
|
+
airgap_toleranz = -(self.max_dist - self.min_dist) / 50.0 # 2%
|
1365
|
+
else:
|
1366
|
+
self.close_to_ag = np.isclose(r_in, self.min_dist, rtol=1e-9, atol=0.005)
|
1367
|
+
close_to_opposition = greater_equal(self.max_dist * 1.05, r_out)
|
1368
|
+
airgap_radius = r_in
|
1369
|
+
opposite_radius = r_out
|
1370
|
+
airgap_toleranz = (self.max_dist - self.min_dist) / 50.0 # 2%
|
1371
|
+
|
1372
|
+
self.close_to_startangle = np.isclose(self.min_angle, startangle,
|
1373
|
+
1e-04, 1e-04)
|
1374
|
+
self.close_to_endangle = np.isclose(self.max_angle, endangle,
|
1375
|
+
1e-04, 1e-04)
|
1376
|
+
|
1377
|
+
logger.debug("\n***** mark_EESM_rotor_subregions [{}] *****"
|
1378
|
+
.format(self.id))
|
1379
|
+
logger.debug(" - close_to_ag : %s", self.close_to_ag)
|
1380
|
+
logger.debug(" - close_to_opposition: %s", close_to_opposition)
|
1381
|
+
logger.debug(" - min dist : %3.12f", self.min_dist)
|
1382
|
+
logger.debug(" - max dist : %3.12f", self.max_dist)
|
1383
|
+
logger.debug(" - airgap radius : %3.12f", airgap_radius)
|
1384
|
+
logger.debug(" - opposite radius : %3.12f", opposite_radius)
|
1385
|
+
logger.debug(" - close_to_startangle: %s", self.close_to_startangle)
|
1386
|
+
logger.debug(" - close_to_endangle : %s", self.close_to_endangle)
|
1387
|
+
logger.debug(" - alpha : %3.12f", alpha)
|
1388
|
+
logger.debug(" - min_angle : %3.12f", self.min_angle)
|
1389
|
+
logger.debug(" - max_angle : %3.12f", self.max_angle)
|
1390
|
+
|
1391
|
+
if self.has_iron_separator():
|
1392
|
+
logger.debug("***** iron (has iron separator)\n")
|
1393
|
+
self.type = TYPE_IRON # iron
|
1394
|
+
return self.type
|
1395
|
+
|
1396
|
+
if is_inner:
|
1397
|
+
# looking for shaft
|
1398
|
+
if close_to_opposition and not self.close_to_ag:
|
1399
|
+
logger.debug("-- check for shaft")
|
1400
|
+
if self.is_shaft_area(center):
|
1401
|
+
self.type = TYPE_SHAFT # shaft
|
1402
|
+
logger.debug("***** shaft (close to opposition)\n")
|
1403
|
+
return self.type
|
1404
|
+
|
1405
|
+
if close_to_opposition or self.close_to_ag:
|
1406
|
+
self.type = TYPE_IRON # iron
|
1407
|
+
logger.debug("***** iron (close to opposition)\n")
|
1408
|
+
return self.type
|
1409
|
+
|
1410
|
+
self.type = TYPE_WINDINGS_OR_IRON # windings or iron
|
1411
|
+
logger.debug("***** air (somewhere)\n")
|
1412
|
+
return self.type
|
1413
|
+
|
1414
|
+
def mark_PMSM_rotor_subregions(self,
|
1415
|
+
is_inner,
|
1416
|
+
mirrored,
|
1417
|
+
alpha,
|
1418
|
+
center,
|
1419
|
+
r_in,
|
1420
|
+
r_out,
|
1421
|
+
startangle,
|
1422
|
+
endangle):
|
1423
|
+
logger.debug("mark_PMSM_rotor_subregions")
|
1322
1424
|
|
1323
1425
|
alpha = round(alpha, 6)
|
1324
1426
|
|
@@ -1345,7 +1447,7 @@ class Area(object):
|
|
1345
1447
|
self.close_to_endangle = np.isclose(self.max_angle, endangle,
|
1346
1448
|
1e-04, 1e-04)
|
1347
1449
|
|
1348
|
-
logger.debug("\n*****
|
1450
|
+
logger.debug("\n***** mark_PMSM_rotor_subregions [{}] *****"
|
1349
1451
|
.format(self.id))
|
1350
1452
|
logger.debug(" - close_to_ag : %s", self.close_to_ag)
|
1351
1453
|
logger.debug(" - close_to_opposition: %s", close_to_opposition)
|
femagtools/dxfsl/conv.py
CHANGED
@@ -25,6 +25,16 @@ def main():
|
|
25
25
|
description='Process DXF file and create a plot or FSL file.')
|
26
26
|
argparser.add_argument('dxfile',
|
27
27
|
help='name of DXF file')
|
28
|
+
argparser.add_argument('--PMSM',
|
29
|
+
help='Permanent Magnet Synchronous Motor',
|
30
|
+
dest='PMSM',
|
31
|
+
action="store_true",
|
32
|
+
default=False)
|
33
|
+
argparser.add_argument('--EESM',
|
34
|
+
help='Electric Excited Synchronous Motor',
|
35
|
+
dest='EESM',
|
36
|
+
action="store_true",
|
37
|
+
default=False)
|
28
38
|
argparser.add_argument('--inner',
|
29
39
|
help='name of inner element',
|
30
40
|
dest='inner',
|
@@ -209,12 +219,17 @@ def main():
|
|
209
219
|
if args.sym_part not in (3, 4, 6, 8):
|
210
220
|
logger.error("Argument sympart not in (3, 4, 6, 8)")
|
211
221
|
sys.exit(1)
|
222
|
+
if args.EESM:
|
223
|
+
if args.PMSM:
|
224
|
+
logger.error("PMSM or EESM expected (default PMSM)")
|
225
|
+
sys.exit(1)
|
212
226
|
|
213
227
|
if not args.write_fsl:
|
214
228
|
if not (args.show_plots or args.show_areas or args.view):
|
215
229
|
args.write_fsl = True
|
216
230
|
|
217
231
|
res = convert(args.dxfile, # DXF-Filename
|
232
|
+
args.EESM, # motor type EESM or PMSM
|
218
233
|
rtol=args.rtol, # relative pickdist toleranz
|
219
234
|
atol=args.atol, # absolute pickdist toleranz
|
220
235
|
symtol=args.sym_tolerance,
|
femagtools/dxfsl/converter.py
CHANGED
@@ -158,7 +158,7 @@ def symmetry_search(machine,
|
|
158
158
|
return machine_ok
|
159
159
|
|
160
160
|
|
161
|
-
def build_machine_rotor(machine, inner, mindist, plt, single=False):
|
161
|
+
def build_machine_rotor(machine, inner, mindist, plt, EESM=False, single=False):
|
162
162
|
logger.debug("Begin of build_machine_rotor")
|
163
163
|
if machine.has_windings():
|
164
164
|
logger.debug("do nothing here with windings in rotor")
|
@@ -170,7 +170,7 @@ def build_machine_rotor(machine, inner, mindist, plt, single=False):
|
|
170
170
|
machine_temp = machine.undo_mirror()
|
171
171
|
machine_temp.delete_tiny_elements(mindist)
|
172
172
|
machine_temp.geom.set_rotor()
|
173
|
-
machine_temp.search_rotor_subregions(single=single)
|
173
|
+
machine_temp.search_rotor_subregions(EESM, single=single)
|
174
174
|
else:
|
175
175
|
machine_temp = machine
|
176
176
|
|
@@ -199,7 +199,7 @@ def build_machine_rotor(machine, inner, mindist, plt, single=False):
|
|
199
199
|
logger.debug("Auxiliary Lines created: rebuild subregions")
|
200
200
|
rebuild = True
|
201
201
|
if rebuild:
|
202
|
-
machine_temp.rebuild_subregions(single=single)
|
202
|
+
machine_temp.rebuild_subregions(EESM, single=single)
|
203
203
|
|
204
204
|
machine_temp.geom.recalculate_magnet_orientation()
|
205
205
|
if inner:
|
@@ -215,7 +215,7 @@ def build_machine_rotor(machine, inner, mindist, plt, single=False):
|
|
215
215
|
return machine_temp
|
216
216
|
|
217
217
|
|
218
|
-
def build_machine_stator(machine, inner, mindist, plt, single=False):
|
218
|
+
def build_machine_stator(machine, inner, mindist, plt, EESM=False, single=False):
|
219
219
|
logger.debug("Begin of build_machine_stator")
|
220
220
|
if not machine.geom.is_stator():
|
221
221
|
logger.debug("Rotor with windings")
|
@@ -230,7 +230,7 @@ def build_machine_stator(machine, inner, mindist, plt, single=False):
|
|
230
230
|
else:
|
231
231
|
machine_temp = machine
|
232
232
|
if machine_temp.create_auxiliary_lines():
|
233
|
-
machine_temp.rebuild_subregions(single=single)
|
233
|
+
machine_temp.rebuild_subregions(EESM, single=single)
|
234
234
|
|
235
235
|
if inner:
|
236
236
|
machine_temp.create_inner_corner_areas()
|
@@ -246,6 +246,7 @@ def build_machine_stator(machine, inner, mindist, plt, single=False):
|
|
246
246
|
|
247
247
|
|
248
248
|
def convert(dxfile,
|
249
|
+
EESM=False,
|
249
250
|
rtol=1e-04,
|
250
251
|
atol=1e-03,
|
251
252
|
mindist=0.01,
|
@@ -505,34 +506,38 @@ def convert(dxfile,
|
|
505
506
|
|
506
507
|
machine_inner.sync_with_counterpart(machine_outer)
|
507
508
|
|
508
|
-
machine_inner.search_subregions()
|
509
|
-
machine_outer.search_subregions()
|
509
|
+
machine_inner.search_subregions(EESM)
|
510
|
+
machine_outer.search_subregions(EESM)
|
510
511
|
|
511
512
|
# Inner mirrored rotor
|
512
513
|
if machine_inner.geom.is_rotor():
|
513
514
|
machine_inner = build_machine_rotor(machine_inner,
|
514
515
|
True, # is inner
|
515
516
|
mindist,
|
516
|
-
p
|
517
|
+
p,
|
518
|
+
EESM=EESM)
|
517
519
|
|
518
520
|
# Outer mirrored rotor
|
519
521
|
if machine_outer.geom.is_rotor():
|
520
522
|
machine_outer = build_machine_rotor(machine_outer,
|
521
523
|
False, # is outer
|
522
524
|
mindist,
|
523
|
-
p
|
525
|
+
p,
|
526
|
+
EESM=EESM)
|
524
527
|
|
525
528
|
if machine_inner.geom.is_stator() or machine_inner.has_windings():
|
526
529
|
machine_inner = build_machine_stator(machine_inner,
|
527
530
|
True,
|
528
531
|
mindist,
|
529
|
-
p
|
532
|
+
p,
|
533
|
+
EESM=EESM)
|
530
534
|
|
531
535
|
if machine_outer.geom.is_stator() or machine_outer.has_windings():
|
532
536
|
machine_outer = build_machine_stator(machine_outer,
|
533
537
|
False,
|
534
538
|
mindist,
|
535
|
-
p
|
539
|
+
p,
|
540
|
+
EESM=EESM)
|
536
541
|
machine_inner.sync_with_counterpart(machine_outer)
|
537
542
|
|
538
543
|
machine_inner.search_critical_elements(mindist)
|
@@ -707,20 +712,30 @@ def convert(dxfile,
|
|
707
712
|
machine.geom.set_stator()
|
708
713
|
machine.set_inner_or_outer(part[1])
|
709
714
|
machine.search_stator_subregions(single=True)
|
710
|
-
machine = build_machine_stator(machine,
|
715
|
+
machine = build_machine_stator(machine,
|
716
|
+
inner,
|
717
|
+
mindist,
|
718
|
+
p,
|
719
|
+
EESM=EESM,
|
720
|
+
single=True)
|
711
721
|
|
712
722
|
params = create_femag_parameters_stator(machine,
|
713
723
|
part[1])
|
714
724
|
else:
|
715
725
|
machine.geom.set_rotor()
|
716
726
|
machine.set_inner_or_outer(part[1])
|
717
|
-
machine.search_rotor_subregions(single=True)
|
718
|
-
machine = build_machine_rotor(machine,
|
727
|
+
machine.search_rotor_subregions(EESM, single=True)
|
728
|
+
machine = build_machine_rotor(machine,
|
729
|
+
inner,
|
730
|
+
mindist,
|
731
|
+
p,
|
732
|
+
EESM=EESM,
|
733
|
+
single=True)
|
719
734
|
|
720
735
|
params = create_femag_parameters_rotor(machine,
|
721
736
|
part[1])
|
722
737
|
else:
|
723
|
-
machine.search_subregions(single=True)
|
738
|
+
machine.search_subregions(EESM, single=True)
|
724
739
|
|
725
740
|
machine.create_inner_corner_areas()
|
726
741
|
|
femagtools/dxfsl/fslrenderer.py
CHANGED
@@ -254,6 +254,9 @@ class FslRenderer(object):
|
|
254
254
|
if area.type not in subregions:
|
255
255
|
subregions[area.type] = 1
|
256
256
|
num_windings += 1
|
257
|
+
rmin, rmax = area.minmax_dist_from_center((0,0))
|
258
|
+
self.content.append(
|
259
|
+
f'rcoil_{num_windings} = {rmin}, {rmax}')
|
257
260
|
self.content.append('m.xcoil_{}, m.ycoil_{} = x0, y0'.
|
258
261
|
format(num_windings, num_windings))
|
259
262
|
|
femagtools/dxfsl/geom.py
CHANGED
@@ -2478,7 +2478,8 @@ class Geometry(object):
|
|
2478
2478
|
groups_inside = {g.id: g for g in grouplist}
|
2479
2479
|
area.areas_inside = groups_inside
|
2480
2480
|
areas_outside.append(area)
|
2481
|
-
for g in
|
2481
|
+
for g in grouplist:
|
2482
|
+
g.group_is_inside = True
|
2482
2483
|
alist = groups.get(g.id, [])
|
2483
2484
|
alist.append(area)
|
2484
2485
|
groups[g.id] = alist
|
@@ -2532,6 +2533,11 @@ class Geometry(object):
|
|
2532
2533
|
for area in area_list:
|
2533
2534
|
if self.create_aux_lines(area, rightangle, leftangle):
|
2534
2535
|
done = True
|
2536
|
+
main_groups = [g for g in self.areagroup_list
|
2537
|
+
if not g.group_is_inside]
|
2538
|
+
if len(main_groups) > 1:
|
2539
|
+
if self.create_outside_aux_lines(main_groups):
|
2540
|
+
done = True
|
2535
2541
|
else:
|
2536
2542
|
logger.debug("-> start create_auxiliary_lines")
|
2537
2543
|
self.set_areas_inside_for_all_areas()
|
@@ -2856,6 +2862,38 @@ class Geometry(object):
|
|
2856
2862
|
area.get_id())
|
2857
2863
|
return done
|
2858
2864
|
|
2865
|
+
def create_outside_aux_lines(self, grouplist):
|
2866
|
+
done = False
|
2867
|
+
aux_color = 'blue'
|
2868
|
+
aux_linestyle = 'dotted'
|
2869
|
+
|
2870
|
+
i = 0
|
2871
|
+
gaps = []
|
2872
|
+
for group in grouplist:
|
2873
|
+
i += 1
|
2874
|
+
for g in grouplist[i:]:
|
2875
|
+
gaps += group.get_lowest_gap_list(g,
|
2876
|
+
self.center, self.max_radius,
|
2877
|
+
None, None)
|
2878
|
+
gaps.sort()
|
2879
|
+
|
2880
|
+
l = len(grouplist) -1
|
2881
|
+
for d, points, token, id in gaps[:l]:
|
2882
|
+
logger.info("Token %s", token)
|
2883
|
+
line = Line(Element(start=points[0],
|
2884
|
+
end=points[1]),
|
2885
|
+
color=aux_color,
|
2886
|
+
linestyle=aux_linestyle,
|
2887
|
+
attr='outside_auxline')
|
2888
|
+
n1 = self.find_the_node(line.node1(ndec))
|
2889
|
+
n2 = self.find_the_node(line.node2(ndec))
|
2890
|
+
if n1 and n2:
|
2891
|
+
self.add_element(line,
|
2892
|
+
rtol=self.rtol,
|
2893
|
+
atol=self.atol)
|
2894
|
+
done = True
|
2895
|
+
return done
|
2896
|
+
|
2859
2897
|
def set_rotor(self):
|
2860
2898
|
self.sym_counterpart = 1
|
2861
2899
|
self.sym_part = 0
|
@@ -3002,11 +3040,20 @@ class Geometry(object):
|
|
3002
3040
|
for e in elist:
|
3003
3041
|
e.init_attributes('lightblue', 'no_fsl')
|
3004
3042
|
|
3005
|
-
def search_subregions(self, startangle, endangle, single=False):
|
3043
|
+
def search_subregions(self, startangle, endangle, EESM, single=False):
|
3006
3044
|
if self.is_stator():
|
3007
|
-
self.search_stator_subregions(startangle,
|
3045
|
+
self.search_stator_subregions(startangle,
|
3046
|
+
endangle,
|
3047
|
+
single=single)
|
3008
3048
|
elif self.is_rotor():
|
3009
|
-
|
3049
|
+
if EESM:
|
3050
|
+
self.search_EESM_rotor_subregions(startangle,
|
3051
|
+
endangle,
|
3052
|
+
single=single)
|
3053
|
+
else:
|
3054
|
+
self.search_PMSM_rotor_subregions(startangle,
|
3055
|
+
endangle,
|
3056
|
+
single=single)
|
3010
3057
|
else:
|
3011
3058
|
logger.warning("no stator or rotor assigned")
|
3012
3059
|
self.search_unknown_subregions()
|
@@ -3224,25 +3271,88 @@ class Geometry(object):
|
|
3224
3271
|
self.check_shaft_area(shaft_areas[0])
|
3225
3272
|
logger.debug("End of search_stator_subregions")
|
3226
3273
|
|
3227
|
-
def
|
3228
|
-
|
3229
|
-
|
3230
|
-
|
3231
|
-
logger.debug("Begin of
|
3274
|
+
def search_EESM_rotor_subregions(self,
|
3275
|
+
startangle,
|
3276
|
+
endangle,
|
3277
|
+
single=False):
|
3278
|
+
logger.debug("Begin of search_EESM_rotor_subregions")
|
3279
|
+
|
3280
|
+
if self.alfa == 0.0:
|
3281
|
+
self.alfa = np.pi * 2.0
|
3282
|
+
|
3283
|
+
types = {}
|
3284
|
+
for area in self.list_of_areas():
|
3285
|
+
t = area.mark_EESM_rotor_subregions(self.is_inner,
|
3286
|
+
self.is_mirrored(),
|
3287
|
+
self.alfa,
|
3288
|
+
self.center,
|
3289
|
+
self.min_radius,
|
3290
|
+
self.max_radius,
|
3291
|
+
startangle,
|
3292
|
+
endangle)
|
3293
|
+
if t in types:
|
3294
|
+
types[t] += 1
|
3295
|
+
else:
|
3296
|
+
types[t] = 1
|
3297
|
+
|
3298
|
+
windings = [a for a in self.list_of_areas()
|
3299
|
+
if a.is_type(AREA.TYPE_WINDINGS_OR_IRON)]
|
3300
|
+
|
3301
|
+
if self.is_mirrored():
|
3302
|
+
[a.set_type(AREA.TYPE_IRON) for a in windings
|
3303
|
+
if a.close_to_endangle]
|
3304
|
+
wlist = [(a.max_angle, a) for a in self.list_of_areas()
|
3305
|
+
if a.is_type(AREA.TYPE_WINDINGS_OR_IRON)]
|
3306
|
+
if wlist:
|
3307
|
+
wlist.sort(reverse=True)
|
3308
|
+
a, w = wlist[0]
|
3309
|
+
w.set_type(AREA.TYPE_FD_WINDINGS)
|
3310
|
+
else:
|
3311
|
+
midangle = middle_angle(startangle, endangle)
|
3312
|
+
[a.set_type(AREA.TYPE_IRON) for a in windings
|
3313
|
+
if a.max_angle > midangle and a.min_angle < midangle]
|
3314
|
+
windings = [a for a in self.list_of_areas()
|
3315
|
+
if a.is_type(AREA.TYPE_WINDINGS_OR_IRON)]
|
3316
|
+
if len(windings) > 1:
|
3317
|
+
wlist = []
|
3318
|
+
for w in windings:
|
3319
|
+
if w.max_angle < midangle:
|
3320
|
+
angle = alpha_angle(w.max_angle, midangle)
|
3321
|
+
else:
|
3322
|
+
angle = alpha_angle(midangle, w.min_angle)
|
3323
|
+
wlist.append((angle, w))
|
3324
|
+
wlist.sort()
|
3325
|
+
a1, w1 = wlist[0]
|
3326
|
+
a2, w2 = wlist[1]
|
3327
|
+
if np.isclose(a1, a2):
|
3328
|
+
w1.set_type(AREA.TYPE_FD_WINDINGS)
|
3329
|
+
w2.set_type(AREA.TYPE_FD_WINDINGS)
|
3330
|
+
|
3331
|
+
# all remaining areas are in iron
|
3332
|
+
[a.set_type(AREA.TYPE_IRON) for a in self.list_of_areas()
|
3333
|
+
if a.is_type(AREA.TYPE_WINDINGS_OR_IRON)]
|
3334
|
+
|
3335
|
+
logger.debug("End of search_EESM_rotor_subregions")
|
3336
|
+
|
3337
|
+
def search_PMSM_rotor_subregions(self,
|
3338
|
+
startangle,
|
3339
|
+
endangle,
|
3340
|
+
single=False):
|
3341
|
+
logger.debug("Begin of search_PMSM_rotor_subregions")
|
3232
3342
|
|
3233
3343
|
if self.alfa == 0.0:
|
3234
3344
|
self.alfa = np.pi * 2.0
|
3235
3345
|
|
3236
3346
|
types = {}
|
3237
3347
|
for area in self.list_of_areas():
|
3238
|
-
t = area.
|
3239
|
-
|
3240
|
-
|
3241
|
-
|
3242
|
-
|
3243
|
-
|
3244
|
-
|
3245
|
-
|
3348
|
+
t = area.mark_PMSM_rotor_subregions(self.is_inner,
|
3349
|
+
self.is_mirrored(),
|
3350
|
+
self.alfa,
|
3351
|
+
self.center,
|
3352
|
+
self.min_radius,
|
3353
|
+
self.max_radius,
|
3354
|
+
startangle,
|
3355
|
+
endangle)
|
3246
3356
|
if t in types:
|
3247
3357
|
types[t] += 1
|
3248
3358
|
else:
|
@@ -3370,7 +3480,7 @@ class Geometry(object):
|
|
3370
3480
|
self.search_stator_subregions(startangle, endangle, single=single)
|
3371
3481
|
return
|
3372
3482
|
|
3373
|
-
logger.debug("end of
|
3483
|
+
logger.debug("end of search_PMSM_rotor_subregions")
|
3374
3484
|
|
3375
3485
|
def recalculate_magnet_orientation(self):
|
3376
3486
|
logger.debug("begin of recalculate_magnet_orientation")
|
femagtools/dxfsl/machine.py
CHANGED
@@ -1046,21 +1046,36 @@ class Machine(object):
|
|
1046
1046
|
cp_machine.geom.sym_counterpart = self.get_symmetry_part()
|
1047
1047
|
cp_machine.geom.sym_part = cp_machine.get_symmetry_part()
|
1048
1048
|
|
1049
|
-
def search_subregions(self, single=False):
|
1049
|
+
def search_subregions(self, EESM, single=False):
|
1050
1050
|
logger.debug("Search subregions")
|
1051
|
-
self.geom.search_subregions(self.startangle,
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1051
|
+
self.geom.search_subregions(self.startangle,
|
1052
|
+
self.endangle,
|
1053
|
+
EESM,
|
1054
|
+
single=single)
|
1055
|
+
|
1056
|
+
def search_rotor_subregions(self, EESM, single=False):
|
1057
|
+
if EESM:
|
1058
|
+
self.geom.search_EESM_rotor_subregions(self.startangle,
|
1059
|
+
self.endangle,
|
1060
|
+
single=single)
|
1061
|
+
else:
|
1062
|
+
self.geom.search_PMSM_rotor_subregions(self.startangle,
|
1063
|
+
self.endangle,
|
1064
|
+
single=single)
|
1055
1065
|
|
1056
1066
|
def search_stator_subregions(self, single=False):
|
1057
|
-
self.geom.search_stator_subregions(self.startangle,
|
1067
|
+
self.geom.search_stator_subregions(self.startangle,
|
1068
|
+
self.endangle,
|
1069
|
+
single=single)
|
1058
1070
|
|
1059
|
-
def rebuild_subregions(self, single=False):
|
1071
|
+
def rebuild_subregions(self, EESM, single=False):
|
1060
1072
|
logger.debug("Rebuild subregions")
|
1061
1073
|
self.geom.set_edge_attributes()
|
1062
1074
|
self.geom.area_list = []
|
1063
|
-
self.geom.search_subregions(self.startangle,
|
1075
|
+
self.geom.search_subregions(self.startangle,
|
1076
|
+
self.endangle,
|
1077
|
+
EESM,
|
1078
|
+
single=single)
|
1064
1079
|
|
1065
1080
|
def has_windings(self):
|
1066
1081
|
return self.geom.has_windings
|
@@ -1170,7 +1185,9 @@ class Machine(object):
|
|
1170
1185
|
self.geom.area_list = []
|
1171
1186
|
logger.debug("create subregions again")
|
1172
1187
|
self.geom.create_list_of_areas()
|
1173
|
-
self.geom.search_subregions(self.startangle,
|
1188
|
+
self.geom.search_subregions(self.startangle,
|
1189
|
+
self.endangle,
|
1190
|
+
False)
|
1174
1191
|
|
1175
1192
|
logger.debug("end create_mirror_lines_outside_windings")
|
1176
1193
|
|
femagtools/fsl.py
CHANGED
@@ -768,7 +768,10 @@ class Builder:
|
|
768
768
|
|
769
769
|
return (fslmodel + self.create_analysis(sim) +
|
770
770
|
['save_model("close")'])
|
771
|
-
|
771
|
+
|
772
|
+
def create_detailed_wire(self, params, templ):
|
773
|
+
return self.__render(params, templ)
|
774
|
+
|
772
775
|
def __render(self, model, templ, stator=False, magnet=False):
|
773
776
|
if templ.split('.')[-1] in ('fsl', 'mako'):
|
774
777
|
try:
|
femagtools/machine/pm.py
CHANGED
@@ -5,7 +5,7 @@ import logging
|
|
5
5
|
import warnings
|
6
6
|
import numpy as np
|
7
7
|
import numpy.linalg as la
|
8
|
-
from .utils import iqd, betai1, skin_resistance, dqparident, KTH, K
|
8
|
+
from .utils import iqd, betai1, skin_resistance, dqparident, KTH, K, T
|
9
9
|
import scipy.optimize as so
|
10
10
|
import scipy.interpolate as ip
|
11
11
|
import scipy.integrate as ig
|
@@ -14,6 +14,38 @@ from functools import partial
|
|
14
14
|
logger = logging.getLogger(__name__)
|
15
15
|
|
16
16
|
|
17
|
+
def find_peaks_and_valleys(t, iabc, tshort):
|
18
|
+
""" return peaks and valleys of phase current with maximum amplitude
|
19
|
+
"""
|
20
|
+
iph = iabc[np.argmax([np.max(np.abs(iph))
|
21
|
+
for iph in iabc])]
|
22
|
+
ts = t[t>tshort]
|
23
|
+
Z = iph[t>tshort]
|
24
|
+
peaks = (np.diff(np.sign(np.diff(Z))) < 0).nonzero()[0] + 1
|
25
|
+
if len(peaks>0):
|
26
|
+
p = {'ip': Z[peaks].tolist(), 'tp': ts[peaks].tolist()}
|
27
|
+
else:
|
28
|
+
p = {'ip': [], 'tp': []}
|
29
|
+
valleys = (np.diff(np.sign(np.diff(Z))) > 0).nonzero()[0] + 1
|
30
|
+
if len(valleys>0):
|
31
|
+
v = {'iv': Z[valleys].tolist(), 'tv': ts[valleys].tolist()}
|
32
|
+
else:
|
33
|
+
v = {'iv': [], 'tv': []}
|
34
|
+
try:
|
35
|
+
cs = ip.CubicSpline(ts[peaks], Z[peaks])
|
36
|
+
p.update({'i': cs(ts).tolist(), 't': ts.tolist()})
|
37
|
+
except ValueError as e:
|
38
|
+
logger.warning("no peaks in current: %d",
|
39
|
+
len(peaks))
|
40
|
+
try:
|
41
|
+
cs = ip.CubicSpline(ts[valleys], Z[valleys])
|
42
|
+
v.update({'i': cs(ts).tolist(), 't': ts.tolist()})
|
43
|
+
except ValueError as e:
|
44
|
+
logger.warning("no valleys in current: %d",
|
45
|
+
len(valleys))
|
46
|
+
return p, v
|
47
|
+
|
48
|
+
|
17
49
|
def parident(workdir, engine, temp, machine,
|
18
50
|
magnetizingCurves, magnetMat, condMat,
|
19
51
|
**kwargs):
|
@@ -1487,68 +1519,184 @@ class PmRelMachinePsidq(PmRelMachine):
|
|
1487
1519
|
def betai1_plmag(self, beta, i1, f1):
|
1488
1520
|
return self.iqd_plmag(*iqd(beta, i1), f1)
|
1489
1521
|
|
1522
|
+
def ldlqpsim(self):
|
1523
|
+
def ext_array(id, iq, a):
|
1524
|
+
"""extend array a if current is 0 at edge
|
1525
|
+
id: list of n id values
|
1526
|
+
iq: list of m iq values
|
1527
|
+
a: nxm array to extend"""
|
1528
|
+
if id[0] == 0:
|
1529
|
+
y = np.array(a)[:, 1].reshape((-1, 1))
|
1530
|
+
m = np.hstack((y, a))
|
1531
|
+
elif id[-1] == 0:
|
1532
|
+
y = np.array(a)[:, -2].reshape((-1, 1))
|
1533
|
+
m = np.hstack((a, y))
|
1534
|
+
else:
|
1535
|
+
m = np.array(a)
|
1536
|
+
|
1537
|
+
if iq[0] == 0:
|
1538
|
+
return np.concatenate(([m[1]], m))
|
1539
|
+
elif iq[-1] == 0:
|
1540
|
+
return np.concatenate((m, [m[-2]]))
|
1541
|
+
|
1542
|
+
return m
|
1543
|
+
|
1544
|
+
idn = np.append(self.id, -self.id[-2])
|
1545
|
+
iqz = np.where(self.iq == 0.)[0][0]
|
1546
|
+
if iqz in {0, len(self.iq)-1}:
|
1547
|
+
iqn = np.insert(self.iq, 0, -self.iq[1])
|
1548
|
+
elif iqz == len(self.iq)-1:
|
1549
|
+
iqn = np.append(self.iq, -self.iq[iqz-1])
|
1550
|
+
else:
|
1551
|
+
iqn = np.array(self.iq)
|
1552
|
+
psid2 = ext_array(self.id, self.iq, self.psid)
|
1553
|
+
psiq2 = ext_array(self.id, self.iq, self.psiq)
|
1554
|
+
|
1555
|
+
# create n x m matrix of currents
|
1556
|
+
id = np.ones(psid2.shape) * idn
|
1557
|
+
iq = (np.ones(psid2.shape).T * iqn).T
|
1558
|
+
|
1559
|
+
# calculate ec model parameters
|
1560
|
+
psim = (np.ones(psid2.shape).T * psid2[id == 0.]).T
|
1561
|
+
nz = np.any(id != 0., axis=0)
|
1562
|
+
ld = ((psid2-psim)[:, nz])/id[:, nz]
|
1563
|
+
nz = np.any(iq != 0., axis=1)
|
1564
|
+
lq = (psiq2[nz, :])/iq[nz, :]
|
1565
|
+
|
1566
|
+
# create interpolation functions
|
1567
|
+
return (ip.RectBivariateSpline(iq[:, 0], id[0][id[0] != 0], ld),
|
1568
|
+
ip.RectBivariateSpline(iq[:, 0][iq[:, 0] != 0], id[0], lq),
|
1569
|
+
ip.RectBivariateSpline(iq[:, 0], id[0], psim))
|
1570
|
+
|
1490
1571
|
|
1491
1572
|
### EXPERIMENTAL
|
1492
1573
|
|
1493
1574
|
def transient(self, u1, tload, speed,
|
1494
1575
|
fault_type=3, # 'LLL', 'LL', 'LG',
|
1495
|
-
tend=0.1, nsamples=200):
|
1496
|
-
|
1497
|
-
tshort = 0
|
1576
|
+
tshort=0, tend=0.1, nsamples=200):
|
1577
|
+
ns = round(tshort/tend*nsamples), round((tend-tshort)/tend*nsamples)
|
1498
1578
|
w1 = 2*np.pi*self.p*speed
|
1579
|
+
i0 = self.iqd_torque(tload)
|
1499
1580
|
res = so.minimize(
|
1500
|
-
|
1581
|
+
np.linalg.norm, i0, method='SLSQP',
|
1501
1582
|
constraints=(
|
1502
|
-
{'type': '
|
1583
|
+
{'type': 'ineq',
|
1503
1584
|
'fun': lambda iqd: self.tmech_iqd(*iqd, speed) - tload},
|
1504
1585
|
{'type': 'ineq',
|
1505
1586
|
'fun': lambda iqd: np.sqrt(2)*u1
|
1506
1587
|
- la.norm(self.uqd(w1, *iqd))}))
|
1507
1588
|
iqx, idx = res.x
|
1508
1589
|
uq0, ud0 = self.uqd(w1, iqx, idx)
|
1590
|
+
psid = ip.RectBivariateSpline(self.iq, self.id, self.psid, kx=3, ky=3)
|
1591
|
+
psiq = ip.RectBivariateSpline(self.iq, self.id, self.psiq, kx=3, ky=3)
|
1509
1592
|
logger.info("transient: Torque %f Nm, Speed %f rpm, Curr %f A",
|
1510
1593
|
tload, speed*60, betai1(iqx, idx)[1])
|
1594
|
+
#_ld, _lq, _psim = self.ldlqpsim()
|
1595
|
+
#Ld = _ld(iqx, idx)[0, 0]
|
1596
|
+
#Lq = _lq(iqx, idx)[0, 0]
|
1597
|
+
#psim = _psim(iqx, idx)[0, 0]
|
1598
|
+
#logger.info("idx %f iqx %f, Ld %f, Lq %f, psim %f",
|
1599
|
+
# idx, iqx, Ld, Lq, psim)
|
1511
1600
|
if fault_type == 3: # 3 phase short circuit
|
1512
|
-
|
1601
|
+
Y0 = iqx, idx
|
1602
|
+
def U(t):
|
1603
|
+
return (uq0, ud0) if t < tshort else (0, 0)
|
1604
|
+
def didt(t, iqd):
|
1605
|
+
uq, ud = U(t)
|
1606
|
+
ldd = psid(*iqd, dx=0, dy=1)[0,0]
|
1607
|
+
lqq = psiq(*iqd, dx=1, dy=0)[0,0]
|
1608
|
+
ldq = psid(*iqd, dx=1, dy=0)[0,0]
|
1609
|
+
lqd = psiq(*iqd, dx=0, dy=1)[0,0]
|
1610
|
+
psi = psid(*iqd)[0,0], psiq(*iqd)[0,0]
|
1611
|
+
return [
|
1612
|
+
(-ldd*psi[0]*w1 + ldd*(uq-self.r1*iqd[0])
|
1613
|
+
- lqd*psi[1]*w1 - lqd*(ud-self.r1*iqd[1]))/(ldd*lqq - ldq*lqd),
|
1614
|
+
(ldq*psi[0]*w1 - ldq*(uq-self.r1*iqd[0])
|
1615
|
+
+ lqq*psi[1]*w1 + lqq*(ud-self.r1*iqd[1]))/(ldd*lqq - ldq*lqd)]
|
1616
|
+
#def didtl(t, iqd):
|
1617
|
+
# lqd = lq(*iqd)[0,0], ld(*iqd)[0,0]
|
1618
|
+
# return [
|
1619
|
+
# (uq-r1*iqd[0] -w1 * ld*iqd[1] - w1*psim(*iqd)[0,0])/lq,
|
1620
|
+
# (ud-r1*iqd[1] +w1 * lq*iqd[0])/ld]
|
1513
1621
|
else: # 2 phase short circuit
|
1514
|
-
|
1515
|
-
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1519
|
-
|
1520
|
-
|
1521
|
-
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
1539
|
-
(
|
1540
|
-
|
1541
|
-
|
1542
|
-
|
1543
|
-
|
1544
|
-
|
1545
|
-
|
1622
|
+
_ld, _lq, _psim = self.ldlqpsim()
|
1623
|
+
Ld = _ld(iqx, idx)[0, 0]
|
1624
|
+
Lq = _lq(iqx, idx)[0, 0]
|
1625
|
+
psim = _psim(iqx, idx)[0, 0]
|
1626
|
+
Y0 = (0,)
|
1627
|
+
def didt(t, i):
|
1628
|
+
gamma = w1*t
|
1629
|
+
iqd = [2/3*i*(-np.sin(gamma) + np.sin(gamma+2*np.pi/3)),
|
1630
|
+
2/3*i*(np.cos(gamma) + np.cos(gamma+2*np.pi/3))]
|
1631
|
+
ldd = psid(*iqd, dx=0, dy=1)[0,0]
|
1632
|
+
lqq = psiq(*iqd, dx=1, dy=0)[0,0]
|
1633
|
+
ldq = psid(*iqd, dx=1, dy=0)[0,0]
|
1634
|
+
lqd = psiq(*iqd, dx=0, dy=1)[0,0]
|
1635
|
+
psi = psid(*iqd)[0, 0], psiq(*iqd)[0, 0]
|
1636
|
+
A = ((ldd-lqq)*np.cos(2*gamma + np.pi/3)
|
1637
|
+
- (ldq+lqd)*np.sin(2*gamma + np.pi/3) + lqq + ldd)
|
1638
|
+
B = 2/3*w1*((ldd-lqq)*np.sin(2*gamma + np.pi/3)
|
1639
|
+
+ (ldq+lqd)*np.cos(2*gamma + np.pi/3)
|
1640
|
+
+ ldq - lqd) + 2*self.r1
|
1641
|
+
C = np.sqrt(3)*w1*(psi[0]*np.sin(gamma + np.pi/6)
|
1642
|
+
+ psi[1]*np.cos(gamma + np.pi/6))
|
1643
|
+
return -(B*i + C)/A
|
1644
|
+
|
1645
|
+
#def didt2(t, i):
|
1646
|
+
# gamma = w1*t
|
1647
|
+
# idy, iqy = T(gamma).dot([i[0], -i[0], 0])
|
1648
|
+
# ua - ub = 0; ia = -ib; ic = 0
|
1649
|
+
# B = np.sqrt(3)*psim*np.cos(gamma + np.pi/6)
|
1650
|
+
# A = 2*Ld*np.cos(gamma + np.pi/6)**2 + 2*Lq*np.sin(gamma + np.pi/6)**2
|
1651
|
+
# dAdt = 4*w1*np.cos(gamma+np.pi/6)*np.sin(gamma+np.pi/6)*(Ld - Lq)
|
1652
|
+
# dBdt = np.sqrt(3)*w1*psim*np.sin(gamma+np.pi/6)
|
1653
|
+
|
1654
|
+
# return -(i*dAdt + dBdt + 2*self.r1*i)/A
|
1655
|
+
|
1656
|
+
t = np.linspace(tshort, tend, ns[1])
|
1546
1657
|
sol = ig.solve_ivp(didt, (t[0], t[-1]), Y0, dense_output=True)
|
1547
1658
|
y = sol.sol(t).T
|
1548
1659
|
|
1660
|
+
t = np.linspace(0, tend, nsamples)
|
1661
|
+
if fault_type == 3: # 3 phase short circuit
|
1662
|
+
if ns[0] > 0:
|
1663
|
+
iqd = np.vstack(
|
1664
|
+
(np.ones((ns[0], 2)) * (iqx, idx), y))
|
1665
|
+
else:
|
1666
|
+
iqd = y
|
1667
|
+
iabc = np.array([K(w1*x[0]).dot((x[1][1], x[1][0]))
|
1668
|
+
for x in zip(t, iqd)]).T
|
1669
|
+
peaks, valleys = find_peaks_and_valleys(t, iabc, tshort)
|
1670
|
+
|
1671
|
+
#iqx, idx = iqd[-1, 0], iqd[-1, 1],
|
1672
|
+
#Ld = _ld(iqx, idx)[0, 0]
|
1673
|
+
#Lq = _lq(iqx, idx)[0, 0]
|
1674
|
+
#psim = _psim(iqx, idx)[0, 0]
|
1675
|
+
#logger.info("idx %f iqx %f, Ld %f, Lq %f, psim %f",
|
1676
|
+
# idx, iqx, Ld, Lq, psim)
|
1677
|
+
return {
|
1678
|
+
't': t.tolist(),
|
1679
|
+
'iq': iqd[:,0], 'id': iqd[:,1],
|
1680
|
+
'istat': iabc.tolist(),
|
1681
|
+
'peaks': peaks,
|
1682
|
+
'valleys': valleys,
|
1683
|
+
'torque': [self.torque_iqd(*x) for x in iqd]}
|
1684
|
+
if ns[0] > 0:
|
1685
|
+
iabc = np.hstack(
|
1686
|
+
(np.array(
|
1687
|
+
[K(w1*t).dot((idx, iqx))
|
1688
|
+
for t in np.linspace(0, tshort, ns[0])]).T,
|
1689
|
+
[y[:, 0], (-y)[:, 0], np.zeros(ns[1])]))
|
1690
|
+
else:
|
1691
|
+
iabc = np.array(
|
1692
|
+
[y[:, 0], (-y)[:, 0], np.zeros(len(t))])
|
1693
|
+
peaks, valleys = find_peaks_and_valleys(t, iabc, tshort)
|
1694
|
+
idq = np.array([T(w1*x[0]).dot(x[1])
|
1695
|
+
for x in zip(t, iabc.T)]).T
|
1549
1696
|
return {
|
1550
1697
|
't': t.tolist(),
|
1551
|
-
'iq':
|
1552
|
-
'istat':
|
1553
|
-
|
1554
|
-
'
|
1698
|
+
'iq': idq[1], 'id': idq[0],
|
1699
|
+
'istat': iabc.tolist(),
|
1700
|
+
'peaks': peaks,
|
1701
|
+
'valleys': valleys,
|
1702
|
+
'torque': self.torque_iqd(idq[1], idq[0])}
|
femagtools/machine/utils.py
CHANGED
@@ -14,7 +14,7 @@ logger = logging.getLogger(__name__)
|
|
14
14
|
|
15
15
|
def K(d):
|
16
16
|
"""space phasor transformation matrix
|
17
|
-
(Inverse Park Transformation) T-1 * dq
|
17
|
+
(Inverse Park Transformation) T-1 * dq --> abc
|
18
18
|
arguments:
|
19
19
|
d: rotation angle
|
20
20
|
|
@@ -28,7 +28,7 @@ def K(d):
|
|
28
28
|
|
29
29
|
def T(d):
|
30
30
|
"""space phasor transformation matrix
|
31
|
-
(Park Transformation) T * abc
|
31
|
+
(Park Transformation) T * abc --> dq
|
32
32
|
arguments:
|
33
33
|
d: rotation angle
|
34
34
|
|
femagtools/plot/bch.py
CHANGED
@@ -508,19 +508,33 @@ def transientsc(bch, title=''):
|
|
508
508
|
row = 1
|
509
509
|
plt.subplot(rows, cols, row)
|
510
510
|
ax = plt.gca()
|
511
|
-
ax.set_title('Currents / A')
|
512
511
|
ax.grid(True)
|
513
|
-
|
514
|
-
|
512
|
+
istat = np.array([bch.scData[i]
|
513
|
+
for i in ('ia', 'ib', 'ic')])
|
514
|
+
if np.max(istat) > 4000:
|
515
|
+
istat *= 1e-3
|
516
|
+
ax.set_title('Currents / kA')
|
517
|
+
else:
|
518
|
+
ax.set_title('Currents / A')
|
519
|
+
|
520
|
+
for i, iph in zip(('ia', 'ib', 'ic'), istat):
|
521
|
+
ax.plot(bch.scData['time'], iph, label=i)
|
515
522
|
ax.set_xlabel('Time / s')
|
516
523
|
ax.legend()
|
517
524
|
|
518
525
|
row = 2
|
519
526
|
plt.subplot(rows, cols, row)
|
520
527
|
ax = plt.gca()
|
521
|
-
|
528
|
+
scale = 1
|
529
|
+
torque = np.array(bch.scData['torque'])
|
530
|
+
if np.max(torque) > 4000:
|
531
|
+
torque *= 1e-3
|
532
|
+
ax.set_title('Torque / kNm')
|
533
|
+
else:
|
534
|
+
ax.set_title('Torque / Nm')
|
535
|
+
|
522
536
|
ax.grid(True)
|
523
|
-
ax.plot(bch.scData['time'],
|
537
|
+
ax.plot(bch.scData['time'], torque)
|
524
538
|
ax.set_xlabel('Time / s')
|
525
539
|
|
526
540
|
fig.tight_layout(h_pad=2)
|
@@ -14,13 +14,22 @@ if not airgap_created then
|
|
14
14
|
end
|
15
15
|
% if hasattr(model, 'bore_diam'):
|
16
16
|
r1 = m.fc_radius - ag/6
|
17
|
+
if(m.npols_gen == m.num_poles) then
|
18
|
+
alfa = alfa / 2
|
19
|
+
end
|
17
20
|
x1, y1 = pr2c(r1, alfa)
|
18
21
|
n = math.floor(m.fc_radius*alfa/agndst + 1.5)
|
19
22
|
nc_circle_m(r1, 0, x1, y1, 0.0, 0.0, n)
|
23
|
+
if(m.npols_gen == m.num_poles) then
|
24
|
+
nc_circle_m(x1, y1, r1, 0, 0.0, 0.0, n)
|
25
|
+
end
|
20
26
|
|
21
27
|
r2 = m.fc_radius + ag/6
|
22
28
|
x2, y2 = pr2c(r2, alfa)
|
23
29
|
nc_circle_m(r2, 0, x2, y2, 0.0, 0.0, n)
|
30
|
+
if(m.npols_gen == m.num_poles) then
|
31
|
+
nc_circle_m(x2, y2, r2, 0, 0.0, 0.0, n)
|
32
|
+
end
|
24
33
|
|
25
34
|
if inner_da_start == nil then
|
26
35
|
inner_da_start = da2/2
|
@@ -34,6 +34,9 @@ m.slot_top_sh = ${model['slot_top_sh']}
|
|
34
34
|
m.zeroangl = ${model.get('zeroangle',0)}
|
35
35
|
m.rlength = ${model.get('rlength',1)*100}
|
36
36
|
|
37
|
+
% if model.get('ac_loss', False):
|
38
|
+
m.ac_loss = ${model.get('ac_loss', 3)}
|
39
|
+
% endif
|
37
40
|
m.mcvkey_yoke = mcvkey_yoke
|
38
41
|
|
39
42
|
pre_models("STATOR_3")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: femagtools
|
3
|
-
Version: 1.7.
|
3
|
+
Version: 1.7.6
|
4
4
|
Summary: Python API for FEMAG
|
5
5
|
Author-email: Ronald Tanner <tar@semafor.ch>, Dapu Zhang <dzhang@gtisoft.com>, Beat Holm <hob@semafor.ch>, Günther Amsler <amg@semafor.ch>, Nicolas Mauchle <mau@semafor.ch>
|
6
6
|
License: Copyright (c) 2016-2023, Semafor Informatik & Energie AG, Basel
|
@@ -1,9 +1,9 @@
|
|
1
|
-
femagtools/__init__.py,sha256=
|
1
|
+
femagtools/__init__.py,sha256=bsP3-dUn57w5F0J2342CXVQfsk2pVYuVby-g3MuoFjM,1600
|
2
2
|
femagtools/airgap.py,sha256=hELJXe52yUw82JwZ1tGUXUtRhMG2_WSUBVeGkTZSAM8,1900
|
3
3
|
femagtools/amazon.py,sha256=O1ICuv21XDAJi1qK1Sigs2TdS6hDZP19OzvmE2t76wU,12069
|
4
4
|
femagtools/amela.py,sha256=pHjfXzpANI-7oz8MtrqNcyDZ6PxVM91vCJuvYhHy1rk,13891
|
5
5
|
femagtools/asm.py,sha256=CiL0KWaF4P7O6-VwmGLdva_icwmPrPiI-TFQ19XYTKk,7660
|
6
|
-
femagtools/bch.py,sha256=
|
6
|
+
femagtools/bch.py,sha256=FYpQsbCaJB6GJHwUto4aCq94Yz1DtYAbaj7l-gGjmY4,73716
|
7
7
|
femagtools/bchxml.py,sha256=KrRjAdrUPZXmiWvonu9HhpG_NvImMBpiXWTL4iSr4kE,3142
|
8
8
|
femagtools/condor.py,sha256=J8z9iBdvrGu3I1eFNoyKV8AXzRoTEPGLSak6cXUQxAM,10766
|
9
9
|
femagtools/conductor.py,sha256=rXO7c7Qh_s7JpgILmLd4IbG64vP6Eh143YF9u25Mdwg,1076
|
@@ -17,7 +17,7 @@ femagtools/ecloss.py,sha256=gaZ8JmlFVoP6IYe79YXPXvZSULm8IZr6bPBdKuyKaIo,12832
|
|
17
17
|
femagtools/erg.py,sha256=IXKq76P9qLt_ssNOP78v8Qizk3J2Zg80yaKDSjzwoJE,1224
|
18
18
|
femagtools/femag.py,sha256=RUkjvkHe5gBElawh4-cbwueplXA5Tjvnu28CPVw6f74,44123
|
19
19
|
femagtools/forcedens.py,sha256=7NNv75Vg9vQ_fy8W4kM2rlSO970zaSmeurhPmdAxsOU,8485
|
20
|
-
femagtools/fsl.py,sha256=
|
20
|
+
femagtools/fsl.py,sha256=wlQkaFslVhbhLYuFJMddlOAOjWoZfeQgBUi6zNS4s-A,33977
|
21
21
|
femagtools/getset.py,sha256=yJ6Em35DeWK7WNZW0qjjS5s7LUkVh5mbgxF59HHm5FM,3017
|
22
22
|
femagtools/gmsh.py,sha256=IKhNiviIBji4cMxAhxaYXNqBRMNAPSKsBGdnGyxkyQw,3903
|
23
23
|
femagtools/google.py,sha256=ugRyHY1zBjHR4aNfbA7GeF-ZU_NgleuVTZaWpi_XLT4,17144
|
@@ -48,20 +48,20 @@ femagtools/vbf.py,sha256=9XGfhftmD9carU8ByQ5DwqoR4daq5mJ39eMqruwml0Q,2444
|
|
48
48
|
femagtools/vtu.py,sha256=Sf83dHIfCKY2km-MIUHKKoj-JKN4PDX7kkPLZXyIYY4,10723
|
49
49
|
femagtools/windings.py,sha256=-PDqzatXJUaMTR4hI1bbY__AAb3fjwfjiS9FEuR-8N8,22305
|
50
50
|
femagtools/dxfsl/__init__.py,sha256=MywcCdpKPKs4qJBJJgeDsikJFJ2P48dbTuNk303f5pM,76
|
51
|
-
femagtools/dxfsl/area.py,sha256=
|
51
|
+
femagtools/dxfsl/area.py,sha256=Y7qNteasOB54hzo-QkDlHdjcym74FKJVdUrKaCFy23I,60813
|
52
52
|
femagtools/dxfsl/areabuilder.py,sha256=Siu11yRcNJiSCWwc865-OvuVhSmLtRQWysbe1-rUcN0,34197
|
53
53
|
femagtools/dxfsl/concat.py,sha256=F6scwesxyOmfmKQ5kGspNCxA71Yz6QgxFL7lTj3hsaI,13385
|
54
|
-
femagtools/dxfsl/conv.py,sha256=
|
55
|
-
femagtools/dxfsl/converter.py,sha256=
|
54
|
+
femagtools/dxfsl/conv.py,sha256=Z_jf4OTxikr-SoUuBew_wrEj32qcGPyEp7VMtkRJx9M,10747
|
55
|
+
femagtools/dxfsl/converter.py,sha256=txsDdMbQxMLXyAC5LV97ZifO49O5oXu-SRM1wqawSUs,33223
|
56
56
|
femagtools/dxfsl/corner.py,sha256=-XPBcnEau-2-SRHLYzlBqCQGaFfgm_DH2qR1mSaFoAs,1311
|
57
57
|
femagtools/dxfsl/dumprenderer.py,sha256=n4AvInjvGIaC2iKZtQaYXXDyJVSQ3uEOFOLD4-xfKRY,1861
|
58
58
|
femagtools/dxfsl/dxfparser.py,sha256=kyXG0kZfNyOgn96MqBgP8RhOQhppfB5NbyRNNybs1C0,13451
|
59
59
|
femagtools/dxfsl/femparser.py,sha256=O8940Q1Mz8MKng6W8M3s9KfTvhDLJ56tfQWtZEW3xMM,2134
|
60
|
-
femagtools/dxfsl/fslrenderer.py,sha256=
|
60
|
+
femagtools/dxfsl/fslrenderer.py,sha256=6mwQv9D45dgR2rmBovcediwfGEnmLGDAWaIfUo2Qd1o,25257
|
61
61
|
femagtools/dxfsl/functions.py,sha256=F0AjzHfIfq3v-mhDzUOeq3zeYQCEsJl1-XpEyJQsSnQ,11805
|
62
|
-
femagtools/dxfsl/geom.py,sha256
|
62
|
+
femagtools/dxfsl/geom.py,sha256=lHmhuDNNM30fTT6p3-cOBkOUI5MKE6PnQ_ShEYDpm58,169937
|
63
63
|
femagtools/dxfsl/journal.py,sha256=S17B7wsrq5QzIUbjgg0ntvnpgH0thHq9aQXO7GdYlQQ,4265
|
64
|
-
femagtools/dxfsl/machine.py,sha256=
|
64
|
+
femagtools/dxfsl/machine.py,sha256=mMi6_eL4b5aZMF67jUS3bXZyr2RorcV9qfJEntejxUk,50098
|
65
65
|
femagtools/dxfsl/plotrenderer.py,sha256=q2cORuxJEf1Ws6oCY9c0gF6N3kDrcI6WOz3u5Vl6R_c,13823
|
66
66
|
femagtools/dxfsl/shape.py,sha256=ZmWw7VTSJs5rcY1Lh99MKo804mO7dSGHdKMIh-nVBow,59904
|
67
67
|
femagtools/dxfsl/svgparser.py,sha256=R8V2V5jE6JyVfzshJVaPgsSuMlQf_pwJTFvrTrKDxZ0,2905
|
@@ -70,10 +70,10 @@ femagtools/machine/__init__.py,sha256=U8W65K7jr7jDdC1KnJh0WjYd8DFaLnIFVvlh-TKcV9
|
|
70
70
|
femagtools/machine/afpm.py,sha256=hNyDFRLGmCuWRPZl_u1ztJ4pA-Y_mxLaVvg3UJkzRuE,24766
|
71
71
|
femagtools/machine/effloss.py,sha256=sLB8AXYVAE_AL1Ca41A2EDbn9_7u6xNjaYFjmRPoTDg,13578
|
72
72
|
femagtools/machine/im.py,sha256=3Y54AHMZfAjkvgexx2E-5jxNWzaVQ-SyaETCh7gNBYA,38008
|
73
|
-
femagtools/machine/pm.py,sha256=
|
73
|
+
femagtools/machine/pm.py,sha256=IfKQPyrVc2AV78rWy2bW1GB1SvM6Ro-XHhOU7RT95Dk,67677
|
74
74
|
femagtools/machine/sizing.py,sha256=nWCfxbyWfbw5-7xu0qZ6zjWNquEPn3fUH-fQeGb6QUc,24307
|
75
75
|
femagtools/machine/sm.py,sha256=G4fHmZngQSRN9Dum7mHaf36b_CvD-u_AQogIFixlnys,37899
|
76
|
-
femagtools/machine/utils.py,sha256=
|
76
|
+
femagtools/machine/utils.py,sha256=lDbOP4HisdOa7Wi-8xLB1jPvwyM_51SFc-xyJYIz4Eo,21238
|
77
77
|
femagtools/moo/__init__.py,sha256=zinmWEOrsEz6DmMX0Dbn4t6_1UR-p4bEGqyR1wUQk_Q,175
|
78
78
|
femagtools/moo/algorithm.py,sha256=lNEf0Bur4yFpIJeLtAC3oIus8sOMWTb7jepFlD28YzE,5445
|
79
79
|
femagtools/moo/population.py,sha256=qGEsm-2Ys_pTkVQv3Zv36HzOlqUxtMvM6NqY_KytsUE,10060
|
@@ -82,7 +82,7 @@ femagtools/moo/test/AlgorithmTest.py,sha256=KzR1og4bu6NOE61DDKjEMTQdsysmho4LCYmJ
|
|
82
82
|
femagtools/moo/test/PopulationTest.py,sha256=lG9NeWo0xrslfQRa4tgy1Nj23VJMFIlg_vQ9KUBYnRA,5529
|
83
83
|
femagtools/moo/test/ProblemTest.py,sha256=r5XEfY4LPscDb35TxxPd0lbP3nUmL6_G6vrRo1I3RSg,505
|
84
84
|
femagtools/plot/__init__.py,sha256=dD_wvo6sGc8jvJYD1b0Z7oxCE4O9uQ3Igb5DeAjZDWU,939
|
85
|
-
femagtools/plot/bch.py,sha256=
|
85
|
+
femagtools/plot/bch.py,sha256=_EEPPEqtEPeWco3xlQqUuZft1eF-IXbMNnXyd8pYEJs,28873
|
86
86
|
femagtools/plot/char.py,sha256=iDvrKp_Hz10W7qLjWCtYajKjY01fZbwf_kITDGisPaY,12123
|
87
87
|
femagtools/plot/fieldlines.py,sha256=QtKF4nhnQ_FHHGh9Qez3GVmym0CLhW1ZyIKtk4pzos4,1136
|
88
88
|
femagtools/plot/fluxdens.py,sha256=NlexRJ3f_8CgKoWrV82ZIsAXPrLhwj98uOe8_fUks7A,1082
|
@@ -129,7 +129,7 @@ femagtools/templates/magnetSector.mako,sha256=db_i1jNJ4TONkBIEKVIWVRZkEJWPwO_r4M
|
|
129
129
|
femagtools/templates/magnetSectorLinear.mako,sha256=ez2rkZslw66Zy4DCDiLjI2K45nEjGgunl0jsXseO_Zs,727
|
130
130
|
femagtools/templates/magnetShell.mako,sha256=vpyZIZ5tOsrmUVM00Kime7zyu1lK9P61xq78jB8BLdo,1295
|
131
131
|
femagtools/templates/magnetShell2.mako,sha256=4IJBfBTPxuYHr1SAcVvNdQoGd8emwsx8vMKQPI9pRlc,4080
|
132
|
-
femagtools/templates/mesh-airgap.mako,sha256=
|
132
|
+
femagtools/templates/mesh-airgap.mako,sha256=9fESevBQJSIf0uCWJIRqhZaj-2-HEjR3nJl-YfKebPo,3685
|
133
133
|
femagtools/templates/modal_analysis.mako,sha256=Thf62FBqL738qnp1ongPr196GJY27vwElKqPfMWF45s,2298
|
134
134
|
femagtools/templates/modified_steinmetz.mako,sha256=qrJ18XtoU39kjbcdywCJCLObQGaO-eC3Cl-1P4xLZWg,1327
|
135
135
|
femagtools/templates/mult_cal_fast.mako,sha256=FhqRZQaBIIvmx0LgKXVLOIjz7LshoDFHqhkD0QGlX8A,1255
|
@@ -157,7 +157,7 @@ femagtools/templates/stator3Linear.mako,sha256=pNe3C1wT0W2C0qePo3sEyebW1z_dpTuJz
|
|
157
157
|
femagtools/templates/stator4.mako,sha256=Jq8pfIuOmmpyGOL1z2aQZfbwMS5-Zyn6OGJ51LCBVKs,1179
|
158
158
|
femagtools/templates/statorBG.mako,sha256=fh0cVOZVWyLojlGxWJoFz2pvdL6Yxy4xzhY-Joc2xeg,893
|
159
159
|
femagtools/templates/statorRing.mako,sha256=sDgDmk71EoE8d4e9cmyqKqRldfC8uKMmpHEjXJGIt_k,2071
|
160
|
-
femagtools/templates/statorRotor3.mako,sha256=
|
160
|
+
femagtools/templates/statorRotor3.mako,sha256=6NTmHKetgsfi4tsN_OSNqZ08y_KVXLOMs7VkeN6Bngk,5025
|
161
161
|
femagtools/templates/stator_msh.mako,sha256=Neze1ielMCk7TrARyhOra91fFQVT8Phsgk2Omt_aMG8,1799
|
162
162
|
femagtools/templates/therm-dynamic.mako,sha256=pEz7jrUpopK1-RqgulNnrkSaCZDjfLelsVo6cBqmpac,3142
|
163
163
|
femagtools/templates/therm_static.mako,sha256=ulevp4AP-kZ1_qdScPMaX9tLqvvP0t9lFflWTXgUxaE,1310
|
@@ -212,9 +212,9 @@ tests/moo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
212
212
|
tests/moo/test_algorithm.py,sha256=Em8sFm2vzPmuIzRrBBnUQLU_TYuJHSf-kEeozw0XeX4,2563
|
213
213
|
tests/moo/test_population.py,sha256=FvX9LRCxQx0_E2GxHQ5vKwOYFBQiNbT6Lmv5GmNWjTQ,5471
|
214
214
|
tests/moo/test_problem.py,sha256=ALeP4u7g-dFhfwWL8vxivdrrYzVKPjHMCAXzzgyNZbs,467
|
215
|
-
femagtools-1.7.
|
216
|
-
femagtools-1.7.
|
217
|
-
femagtools-1.7.
|
218
|
-
femagtools-1.7.
|
219
|
-
femagtools-1.7.
|
220
|
-
femagtools-1.7.
|
215
|
+
femagtools-1.7.6.dist-info/LICENSE,sha256=NaQe4uvkszQPJmiRPHecfk-Ab9VSRXo8xQLGNVHTeFo,1362
|
216
|
+
femagtools-1.7.6.dist-info/METADATA,sha256=dTUdOh7eh4dgbkfeUTUDK1OPxGSMniFY3sSxQNl_BGg,6156
|
217
|
+
femagtools-1.7.6.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
|
218
|
+
femagtools-1.7.6.dist-info/entry_points.txt,sha256=jrvOkZPiN44u1sASeu271VRaVIv5V-uRpN0_N5U_R8c,248
|
219
|
+
femagtools-1.7.6.dist-info/top_level.txt,sha256=Ri4YWtU8MZTzNje9IKyXhTakNbsrCynuWdon4Yq94Dc,17
|
220
|
+
femagtools-1.7.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|