femagtools 1.3.1__py3-none-any.whl → 1.3.2__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/airgap.py +11 -37
- femagtools/amela.py +2 -1
- femagtools/bch.py +19 -3
- femagtools/dxfsl/area.py +56 -15
- femagtools/dxfsl/converter.py +2 -0
- femagtools/dxfsl/geom.py +160 -41
- femagtools/dxfsl/machine.py +80 -3
- femagtools/ecloss.py +5 -3
- femagtools/femag.py +7 -1
- femagtools/isa7.py +35 -22
- femagtools/machine/effloss.py +4 -1
- femagtools/machine/utils.py +12 -8
- femagtools/model.py +11 -1
- femagtools/plot.py +33 -9
- femagtools/templates/afm_rotor.mako +102 -0
- femagtools/templates/afm_stator.mako +141 -0
- femagtools/templates/basic_modpar.mako +23 -2
- femagtools/templates/cogg_calc.mako +28 -5
- femagtools/templates/cu_losses.mako +1 -1
- femagtools/templates/fieldcalc.mako +39 -0
- femagtools/templates/gen_winding.mako +52 -47
- femagtools/templates/mesh-airgap.mako +43 -0
- femagtools/templates/stator3Linear.mako +5 -4
- femagtools/templates/therm-static.mako +12 -0
- femagtools/templates/torq_calc.mako +2 -4
- femagtools/utils.py +45 -0
- femagtools/windings.py +2 -1
- {femagtools-1.3.1.dist-info → femagtools-1.3.2.dist-info}/METADATA +1 -1
- {femagtools-1.3.1.dist-info → femagtools-1.3.2.dist-info}/RECORD +34 -30
- {femagtools-1.3.1.dist-info → femagtools-1.3.2.dist-info}/WHEEL +1 -1
- {femagtools-1.3.1.dist-info → femagtools-1.3.2.dist-info}/LICENSE +0 -0
- {femagtools-1.3.1.dist-info → femagtools-1.3.2.dist-info}/entry_points.txt +0 -0
- {femagtools-1.3.1.dist-info → femagtools-1.3.2.dist-info}/top_level.txt +0 -0
femagtools/dxfsl/machine.py
CHANGED
@@ -713,21 +713,98 @@ class Machine(object):
|
|
713
713
|
def delete_tiny_elements(self, mindist):
|
714
714
|
self.geom.delete_tiny_elements(mindist)
|
715
715
|
|
716
|
+
def create_arc(self, radius):
|
717
|
+
arc = Arc(Element(center=self.center,
|
718
|
+
radius=radius,
|
719
|
+
start_angle=(self.startangle-0.1)*180/np.pi,
|
720
|
+
end_angle=(self.endangle+0.1)*180/np.pi),
|
721
|
+
color='red')
|
722
|
+
pts = self.geom.split_and_get_intersect_points(arc)
|
723
|
+
if len(pts) != 2:
|
724
|
+
logger.warning("create_arc(): Bad Points: %s", pts)
|
725
|
+
# self.geom.add_edge(arc.node1(4), arc.node2(4), arc)
|
726
|
+
return False
|
727
|
+
|
728
|
+
arc = Arc(Element(center=self.center,
|
729
|
+
radius=radius,
|
730
|
+
start_angle=self.startangle*180/np.pi,
|
731
|
+
end_angle=self.endangle*180/np.pi))
|
732
|
+
n = self.geom.find_nodes(pts[0], pts[1])
|
733
|
+
self.geom.add_edge(n[0], n[1], arc)
|
734
|
+
return True
|
735
|
+
|
736
|
+
def get_iron_separator(self, radius_list):
|
737
|
+
if len(radius_list) < 2:
|
738
|
+
return 0.0
|
739
|
+
|
740
|
+
r_min = radius_list[0][0]
|
741
|
+
for r in radius_list[1:]:
|
742
|
+
if np.isclose(r[2], r_min, atol=0.001):
|
743
|
+
return r[2]
|
744
|
+
r_min = r[0]
|
745
|
+
|
746
|
+
return 0.0
|
747
|
+
|
716
748
|
def create_mirror_lines_outside_windings(self):
|
749
|
+
logger.debug("create_mirror_lines_outside_windings")
|
750
|
+
|
717
751
|
if not self.geom.has_areas_touching_both_sides():
|
752
|
+
logger.debug("end create_mirror_lines_outside_windings: not done")
|
718
753
|
return
|
719
754
|
|
755
|
+
radius = self.radius+10
|
756
|
+
ag_list = self.geom.detect_airgaps(self.center,
|
757
|
+
self.startangle, self.endangle,
|
758
|
+
atol=0.001,
|
759
|
+
with_end=True)
|
760
|
+
radius_list = [(ag[0], (ag[0] + ag[1]) / 2, ag[1]) for ag in ag_list]
|
761
|
+
radius_list.sort(reverse=True)
|
762
|
+
|
720
763
|
midangle = middle_angle(self.startangle, self.endangle)
|
721
|
-
|
722
|
-
|
723
|
-
|
764
|
+
line = Line(
|
765
|
+
Element(start=self.center,
|
766
|
+
end=point(self.center, radius, midangle)))
|
767
|
+
|
768
|
+
pts = self.geom.split_and_get_intersect_points(line, aktion=False)
|
724
769
|
pts.sort()
|
770
|
+
|
771
|
+
p_critical = self.geom.critical_touch_point(pts)
|
772
|
+
if p_critical:
|
773
|
+
d_critical = distance(self.center, p_critical)
|
774
|
+
logger.info("Critical Point: %s, len=%s", p_critical, d_critical)
|
775
|
+
sep_radius = self.get_iron_separator(radius_list)
|
776
|
+
logger.debug("Iron Separator found: %s", sep_radius)
|
777
|
+
if sep_radius > 0.0 and sep_radius < d_critical:
|
778
|
+
radius = sep_radius
|
779
|
+
else:
|
780
|
+
for r in radius_list:
|
781
|
+
logger.debug("Gap Radius = %s", r[1])
|
782
|
+
if r[1] < d_critical:
|
783
|
+
if self.create_arc(r[1]):
|
784
|
+
radius = r[1]
|
785
|
+
break
|
786
|
+
# else:
|
787
|
+
# sep_radius = self.get_iron_separator(radius_list)
|
788
|
+
# if sep_radius > 0.0:
|
789
|
+
# logger.debug("Iron Separator found: %s", sep_radius)
|
790
|
+
# radius = sep_radius
|
791
|
+
|
792
|
+
# install line
|
793
|
+
line = Line(
|
794
|
+
Element(start=self.center,
|
795
|
+
end=point(self.center, radius, midangle)))
|
796
|
+
|
797
|
+
pts = self.geom.split_and_get_intersect_points(line)
|
798
|
+
pts.sort()
|
799
|
+
|
725
800
|
if self.geom.create_lines_outside_windings(pts):
|
726
801
|
self.geom.area_list = []
|
727
802
|
logger.debug("create subregions again")
|
728
803
|
self.geom.create_list_of_areas()
|
729
804
|
self.geom.search_subregions()
|
730
805
|
|
806
|
+
logger.debug("end create_mirror_lines_outside_windings")
|
807
|
+
|
731
808
|
def check_and_correct_geom(self, what):
|
732
809
|
geom = self.geom.check_geom(what)
|
733
810
|
if geom:
|
femagtools/ecloss.py
CHANGED
@@ -115,7 +115,7 @@ class MagnLoss(Amela):
|
|
115
115
|
self.tgrid = 60/self.speed*(self.theta[-1] - self.theta[0])/360
|
116
116
|
self.lt = len(self.theta)
|
117
117
|
self.ls = self.pm[-1][-1]['ls']
|
118
|
-
|
118
|
+
self.th_loss = []
|
119
119
|
try:
|
120
120
|
self.numpoles = self.pm[-1][-1]['numpoles']
|
121
121
|
except KeyError:
|
@@ -351,7 +351,7 @@ class MagnLoss(Amela):
|
|
351
351
|
with warnings.catch_warnings():
|
352
352
|
warnings.simplefilter('ignore')
|
353
353
|
px_se[iy,ix,c] = self.calc_pvpm(bx_fft[iy,ix,c], max(c/self.tgrid, 1e-6),
|
354
|
-
mu[iy], wm/self.segx[jj],
|
354
|
+
mu[iy], hm, wm/self.segx[jj], 0)
|
355
355
|
|
356
356
|
if mu[iy] < 2:
|
357
357
|
with warnings.catch_warnings():
|
@@ -374,6 +374,7 @@ class MagnLoss(Amela):
|
|
374
374
|
all_load_cases = []
|
375
375
|
for k in self.pm:
|
376
376
|
ialh_loss = 0
|
377
|
+
loss_detail = []
|
377
378
|
for i in k:
|
378
379
|
logger.info(f'magnet width and height: {i["wm"]:.2f}mm {i["hm"]:.2f}mm')
|
379
380
|
[nt, bx_fft, by_fft] = self.periodicity_id(i['bl'])
|
@@ -383,9 +384,10 @@ class MagnLoss(Amela):
|
|
383
384
|
i[j]*=1e-3
|
384
385
|
self.consider_bx(i['wm'], i['hm'], bx_fft, by_fft)
|
385
386
|
bfft = self.bpm_fft(nx, ny, nt, i['elcp'], i['bl'])
|
386
|
-
#loss = self.loss(bfft[0], bfft[1], bfft[2], bfft[3], i['wm'], i['hm'])
|
387
387
|
loss = self.loss(*bfft, i['wm'], i['hm'])
|
388
388
|
ialh_loss += loss
|
389
|
+
loss_detail.append([i['spel_key'], loss/self.numpoles])
|
390
|
+
self.th_loss.append(loss_detail)
|
389
391
|
all_load_cases.append(ialh_loss)
|
390
392
|
|
391
393
|
return all_load_cases
|
femagtools/femag.py
CHANGED
@@ -492,7 +492,8 @@ class Femag(BaseFemag):
|
|
492
492
|
return {'t': ttemp[0], 'temperature': ttemp[1]}
|
493
493
|
|
494
494
|
bch = self.read_bch(self.modelname)
|
495
|
-
if simulation['calculationMode'] == 'pm_sym_fast'
|
495
|
+
if simulation['calculationMode'] == 'pm_sym_fast' or \
|
496
|
+
simulation['calculationMode'] == 'torq_calc':
|
496
497
|
if simulation.get('shortCircuit', False):
|
497
498
|
logger.info("short circuit simulation")
|
498
499
|
simulation.update(
|
@@ -550,6 +551,11 @@ class Femag(BaseFemag):
|
|
550
551
|
bch.losses[i].update({"magnetH": magn_losses[i]})
|
551
552
|
except:
|
552
553
|
pass
|
554
|
+
# pass losses to bch object for th usage
|
555
|
+
try:
|
556
|
+
bch.magnet_loss_th = m.th_loss
|
557
|
+
except:
|
558
|
+
pass
|
553
559
|
return bch
|
554
560
|
return dict(status='ok', message=self.modelname)
|
555
561
|
|
femagtools/isa7.py
CHANGED
@@ -196,7 +196,9 @@ class Reader(object):
|
|
196
196
|
self.el_fe_induction_1.append([[]])
|
197
197
|
self.el_fe_induction_2.append([[]])
|
198
198
|
for i in range(NUM_FE_EVAL_MOVE_STEP + 1):
|
199
|
-
self.
|
199
|
+
b = self.next_block("h")
|
200
|
+
logger.debug("el_fe_induction move step %d: %d", i, len(b))
|
201
|
+
self.el_fe_induction_1[0][0].append(b)
|
200
202
|
self.el_fe_induction_2[0][0].append(self.next_block("h"))
|
201
203
|
|
202
204
|
FC_NUM_MOVE_CALC_LOAD_PMS, FC_NUM_FLX = self.next_block("i")[0:2]
|
@@ -270,7 +272,9 @@ class Reader(object):
|
|
270
272
|
self.el_fe_induction_2.append([[]])
|
271
273
|
self.eddy_cu_vpot.append([[]])
|
272
274
|
for i in range(NUM_FE_EVAL_MOVE_STEP + 1):
|
273
|
-
self.
|
275
|
+
b = self.next_block("h")
|
276
|
+
logger.debug("el_fe_induction move losses step %d: %d", i, len(b))
|
277
|
+
self.el_fe_induction_1[1][0].append(b)
|
274
278
|
self.el_fe_induction_2[1][0].append(self.next_block("h"))
|
275
279
|
for i in range(NUM_FE_EVAL_MOVE_STEP + 1):
|
276
280
|
self.eddy_cu_vpot[1][0].append(self.next_block("h"))
|
@@ -335,7 +339,10 @@ class Reader(object):
|
|
335
339
|
self.el_fe_induction_2.append([[]])
|
336
340
|
self.eddy_cu_vpot.append([[]])
|
337
341
|
for i in range(NUM_FE_EVAL_MOVE_STEP + 1):
|
338
|
-
self.
|
342
|
+
b = self.next_block("h")
|
343
|
+
logger.debug("el_fe_induction move losses (2) step %d: %d",
|
344
|
+
i, len(b))
|
345
|
+
self.el_fe_induction_1[2][0].append(b)
|
339
346
|
self.el_fe_induction_2[2][0].append(self.next_block("h"))
|
340
347
|
for i in range(NUM_FE_EVAL_MOVE_STEP + 1):
|
341
348
|
self.eddy_cu_vpot[2][0].append(self.next_block("h"))
|
@@ -688,25 +695,31 @@ class Isa7(object):
|
|
688
695
|
self.curr_loss = np.array([c/np.sqrt(2) for c in reader.curr_loss])
|
689
696
|
except AttributeError:
|
690
697
|
pass
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
698
|
+
|
699
|
+
try:
|
700
|
+
el_fe_ind = [np.array(reader.el_fe_induction_1).T/1000,
|
701
|
+
np.array(reader.el_fe_induction_2).T/1000]
|
702
|
+
eddy_cu_vpot = np.array(reader.eddy_cu_vpot).T/1000
|
703
|
+
except (ValueError, TypeError) as e:
|
704
|
+
# inhomogenous array
|
705
|
+
l = len(reader.el_fe_induction_1[0][0])
|
706
|
+
shape = []
|
707
|
+
for i in reader.el_fe_induction_1:
|
708
|
+
for j in i:
|
709
|
+
n = 0
|
710
|
+
for k in j:
|
711
|
+
if len(k) < l:
|
712
|
+
break
|
713
|
+
n += 1
|
714
|
+
if n > 0:
|
715
|
+
shape.append(n)
|
716
|
+
el_fe_ind = [np.array([[reader.el_fe_induction_1[0][0][:shape[0]]]]).T/1000,
|
717
|
+
np.array([[reader.el_fe_induction_2[0][0][:shape[0]]]]).T/1000]
|
718
|
+
eddy_cu_vpot = np.array([[reader.eddy_cu_vpot[0][0][:shape[0]]]]).T/1000
|
719
|
+
|
720
|
+
self.el_fe_induction_1 = el_fe_ind[0]
|
721
|
+
self.el_fe_induction_2 = el_fe_ind[1]
|
722
|
+
self.eddy_cu_vpot = eddy_cu_vpot
|
710
723
|
|
711
724
|
self.iron_loss_coefficients = getattr(
|
712
725
|
reader, 'iron_loss_coefficients', [])
|
femagtools/machine/effloss.py
CHANGED
@@ -269,7 +269,10 @@ def efficiency_losses_map(eecpars, u1, T, temp, n, npoints=(60, 40),
|
|
269
269
|
u1 = np.array(r['u1'])
|
270
270
|
i1 = np.array(r['i1'])
|
271
271
|
try:
|
272
|
-
|
272
|
+
if isinstance(eecpars, dict):
|
273
|
+
tfric = eecpars['kfric_b']*eecpars['rotor_mass']*30e-3/np.pi
|
274
|
+
else:
|
275
|
+
tfric = m.tfric
|
273
276
|
except KeyError:
|
274
277
|
tfric = 0
|
275
278
|
|
femagtools/machine/utils.py
CHANGED
@@ -346,6 +346,7 @@ def dqparident(workdir, engine, temp, machine,
|
|
346
346
|
speed: rotor speed in 1/s (default 160/p)
|
347
347
|
i1_max: maximum current in A rms (default approx 3*i1nom)
|
348
348
|
period_frac: fraction of rotating angle (default 6)
|
349
|
+
cmd: femag executable
|
349
350
|
"""
|
350
351
|
import pathlib
|
351
352
|
|
@@ -368,13 +369,16 @@ def dqparident(workdir, engine, temp, machine,
|
|
368
369
|
period_frac = 1 # TODO: missing femag support
|
369
370
|
|
370
371
|
# winding resistance
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
372
|
+
wpar = {'Q': machine['stator']['num_slots'],
|
373
|
+
'm': machine['windings']['num_phases'],
|
374
|
+
'p': machine['poles']//2}
|
375
|
+
|
376
|
+
if 'coil_span' in machine['windings']:
|
377
|
+
wpar['yd'] = machine['windings']['coil_span']
|
378
|
+
if 'num_layers' in machine['windings']:
|
379
|
+
wpar['l'] = machine['windings']['num_layers']
|
380
|
+
|
381
|
+
wdg = windings.Winding(wpar)
|
378
382
|
|
379
383
|
lfe = machine['lfe']
|
380
384
|
g = machine['windings'].get('num_par_wdgs', 1)
|
@@ -401,7 +405,7 @@ def dqparident(workdir, engine, temp, machine,
|
|
401
405
|
parvar = parstudy.List(
|
402
406
|
workdir, condMat=condMat,
|
403
407
|
magnetizingCurves=magnetizingCurves,
|
404
|
-
magnets=magnetMat)
|
408
|
+
magnets=magnetMat, cmd=kwargs.get('cmd', None))
|
405
409
|
|
406
410
|
leakfile = pathlib.Path(workdir) / 'end_wind_leak.dat'
|
407
411
|
leakfile.unlink(missing_ok=True)
|
femagtools/model.py
CHANGED
@@ -11,6 +11,7 @@
|
|
11
11
|
import logging
|
12
12
|
import string
|
13
13
|
import numpy as np
|
14
|
+
from . import windings
|
14
15
|
|
15
16
|
logger = logging.getLogger(__name__)
|
16
17
|
#
|
@@ -156,8 +157,17 @@ class MachineModel(Model):
|
|
156
157
|
for mcv in ('mcvkey_yoke', 'mcvkey_shaft'):
|
157
158
|
if mcv not in self.magnet:
|
158
159
|
self.magnet[mcv] = 'dummy'
|
159
|
-
if 'coord_system' in parameters:
|
160
|
+
if 'coord_system' in parameters or 'afmtype' in parameters:
|
160
161
|
self.move_action = 1
|
162
|
+
wdg = windings.Winding({'Q': self.stator['num_slots'],
|
163
|
+
'p': self.poles//2,
|
164
|
+
'm': self.windings.get('num_phases', 3),
|
165
|
+
'l': self.windings.get('num_layers', 1)})
|
166
|
+
self.windings['wdgscheme'] = ''.join([
|
167
|
+
'{'] + [','.join([''.join(['{']+[','.join([''.join([
|
168
|
+
'{', ','.join(
|
169
|
+
[str(n) for n in z]), '}']) for z in l])] + ['}'])
|
170
|
+
for l in wdg.zoneplan()])] + ['}'])
|
161
171
|
else:
|
162
172
|
self.coord_system = 0
|
163
173
|
self.move_action = 0
|
femagtools/plot.py
CHANGED
@@ -229,7 +229,7 @@ def airgap_fft(airgap, bmin=1e-2, ax=0):
|
|
229
229
|
pass
|
230
230
|
|
231
231
|
|
232
|
-
def torque(pos, torque, ax=0):
|
232
|
+
def torque(pos, torque, title='', ax=0):
|
233
233
|
"""creates plot from torque vs position"""
|
234
234
|
k = 20
|
235
235
|
alpha = np.linspace(pos[0], pos[-1],
|
@@ -242,7 +242,10 @@ def torque(pos, torque, ax=0):
|
|
242
242
|
unit = 'kNm'
|
243
243
|
if ax == 0:
|
244
244
|
ax = plt.gca()
|
245
|
-
|
245
|
+
if title:
|
246
|
+
ax.set_title(title)
|
247
|
+
else:
|
248
|
+
ax.set_title('Torque / {}'.format(unit))
|
246
249
|
ax.grid(True)
|
247
250
|
ax.plot(pos, [scale*t for t in torque], 'go')
|
248
251
|
ax.plot(alpha, scale*f(alpha))
|
@@ -1344,8 +1347,9 @@ def loss_density(isa, subreg=[], ax=0):
|
|
1344
1347
|
sr = subreg
|
1345
1348
|
else:
|
1346
1349
|
sr = [subreg]
|
1347
|
-
elements = [e
|
1348
|
-
for
|
1350
|
+
elements = [e
|
1351
|
+
for s in sr
|
1352
|
+
for e in isa.get_subregion(s).elements()]
|
1349
1353
|
else:
|
1350
1354
|
elements = [e for e in isa.elements]
|
1351
1355
|
|
@@ -1774,7 +1778,7 @@ def get_nT_boundary(n, T):
|
|
1774
1778
|
bnd[1].append((nx, tx))
|
1775
1779
|
return np.array(bnd[0] + bnd[1][::-1])
|
1776
1780
|
|
1777
|
-
def normalize10(v):
|
1781
|
+
def normalize10(v, **kwargs):
|
1778
1782
|
"""
|
1779
1783
|
Normalizes the input-array using the nearest (ceiling) power of 10.
|
1780
1784
|
|
@@ -1785,12 +1789,32 @@ def normalize10(v):
|
|
1785
1789
|
normalized array
|
1786
1790
|
normalisation factor (power of 10)
|
1787
1791
|
"""
|
1788
|
-
|
1792
|
+
n_type = kwargs.get('n_type', 'abs') # 'norm')
|
1793
|
+
r_type = kwargs.get('r_type', 'round') # 'floor')
|
1794
|
+
if n_type == 'norm':
|
1795
|
+
norm = np.log10(np.linalg.norm(v))
|
1796
|
+
elif n_type == 'abs':
|
1797
|
+
norm = np.log10(np.max(np.abs(v)))
|
1798
|
+
else:
|
1799
|
+
raise AttributeError('Unknown norm-type. Allowed values are: "norm", "abs".')
|
1800
|
+
|
1801
|
+
if r_type == 'floor':
|
1802
|
+
norm = 10 ** np.floor(norm)
|
1803
|
+
elif r_type == 'ceil':
|
1804
|
+
norm = 10 ** np.ceil(norm)
|
1805
|
+
elif r_type == 'round':
|
1806
|
+
norm = 10 ** np.round(norm)
|
1807
|
+
else:
|
1808
|
+
raise AttributeError('Unknown rounding type. Allowed values are: "floor", "ceil", "round".')
|
1809
|
+
# norm = 10**(np.ceil(np.log10(np.max(np.abs(v)))))
|
1810
|
+
# norm = 10 ** (np.ceil(np.log10(np.linalg.norm(v))))
|
1811
|
+
# norm = 10 ** (np.floor(np.log10(np.max(np.abs(v)))))
|
1812
|
+
# norm = 10 ** (np.floor(np.log10(np.linalg.norm(v))))
|
1789
1813
|
return v / norm, norm
|
1790
1814
|
|
1791
1815
|
|
1792
1816
|
def plot_contour(speed, torque, z, ax, title='', levels=[],
|
1793
|
-
clabel=True, cmap='YlOrRd', cbar=False):
|
1817
|
+
clabel=True, cmap='YlOrRd', cbar=False, **kwargs):
|
1794
1818
|
""" contour plot of speed, torque, z values
|
1795
1819
|
Arguments:
|
1796
1820
|
levels: (list of floats)
|
@@ -1807,8 +1831,8 @@ def plot_contour(speed, torque, z, ax, title='', levels=[],
|
|
1807
1831
|
x = 60*np.asarray(speed)
|
1808
1832
|
y = np.asarray(torque)
|
1809
1833
|
|
1810
|
-
x, xscale = normalize10(x)
|
1811
|
-
y, yscale = normalize10(y)
|
1834
|
+
x, xscale = normalize10(x, **kwargs)
|
1835
|
+
y, yscale = normalize10(y, **kwargs)
|
1812
1836
|
|
1813
1837
|
if not levels:
|
1814
1838
|
if max(z) <= 1:
|
@@ -0,0 +1,102 @@
|
|
1
|
+
-- Create model of the rotor of the axial flow machine
|
2
|
+
|
3
|
+
m.yoke_height = ${model['yoke_height']*1e3} -- Yoke height [mm]
|
4
|
+
m.magn_height = ${model['magn_height']*1e3} -- Magnet height [mm]
|
5
|
+
m.magn_width = ${model['rel_magn_width']*1e2} -- Magnet width: >0:[%]; <0: [mm]
|
6
|
+
m.spoke_width = ${model['spoke_width']*1e3} -- Spoke width: >0 magn_width will be calculated
|
7
|
+
m.gap_ma_yoke = 0
|
8
|
+
m.nodedist = ${model.get('nodedist', 1)}
|
9
|
+
--@param m.npols_gen -- Number of poles generated
|
10
|
+
|
11
|
+
|
12
|
+
if (m.model_type == "S2R1") or (m.model_type == "S2R1_all") then
|
13
|
+
if (m.yoke_height > 0) then
|
14
|
+
m.yoke_height = 0
|
15
|
+
print("Warning: m.yoke_height for this typ must be 0. Set to 0!")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
if (m.yoke_height > 0) then
|
20
|
+
mh = m.magn_height
|
21
|
+
else
|
22
|
+
mh = m.magn_height/2
|
23
|
+
end
|
24
|
+
|
25
|
+
if m.spoke_width > 0 then
|
26
|
+
m.magn_width = -(m.pole_width-m.spoke_width)
|
27
|
+
end
|
28
|
+
if m.magn_width > 0 then
|
29
|
+
mw = m.magn_width/100*m.pole_width
|
30
|
+
else
|
31
|
+
mw = -m.magn_width
|
32
|
+
end
|
33
|
+
|
34
|
+
fml = require("fml")
|
35
|
+
|
36
|
+
P0 = fml.Point:Create(0, -ag)
|
37
|
+
|
38
|
+
Lh1 = fml.Line:Create(P0,0)
|
39
|
+
Lh2 = fml.Line:Parallel(Lh1,mh)
|
40
|
+
Lh3 = fml.Line:Parallel(Lh2,m.yoke_height)
|
41
|
+
|
42
|
+
Lv1 = fml.Line:Create(P0,90)
|
43
|
+
Lv2 = fml.Line:Parallel(Lv1,(m.pole_width-mw)/2)
|
44
|
+
Lv3 = fml.Line:Parallel(Lv1,(m.pole_width+mw)/2)
|
45
|
+
Lv4 = fml.Line:Parallel(Lv1,m.pole_width)
|
46
|
+
|
47
|
+
P11 = P0
|
48
|
+
P12 = fml.Point:Intersection(Lh2,Lv1)
|
49
|
+
P13 = fml.Point:Intersection(Lh3,Lv1)
|
50
|
+
P21 = fml.Point:Intersection(Lh1,Lv2)
|
51
|
+
P22 = fml.Point:Intersection(Lh2,Lv2)
|
52
|
+
P31 = fml.Point:Intersection(Lh1,Lv3)
|
53
|
+
P32 = fml.Point:Intersection(Lh2,Lv3)
|
54
|
+
P41 = fml.Point:Intersection(Lh1,Lv4)
|
55
|
+
P42 = fml.Point:Intersection(Lh2,Lv4)
|
56
|
+
P43 = fml.Point:Intersection(Lh3,Lv4)
|
57
|
+
|
58
|
+
ndt(m.nodedist)
|
59
|
+
|
60
|
+
nc_line(P11.x,P11.y, P21.x,P21.y, 0)
|
61
|
+
nc_line_cont(P31.x,P31.y, 0)
|
62
|
+
nc_line_cont(P41.x,P41.y, 0)
|
63
|
+
|
64
|
+
nc_line(P12.x,P12.y, P22.x,P22.y, 0)
|
65
|
+
nc_line_cont(P32.x,P32.y, 0)
|
66
|
+
nc_line_cont(P42.x,P42.y, 0)
|
67
|
+
|
68
|
+
nc_line(P11.x,P11.y, P12.x,P12.y, 0)
|
69
|
+
nc_line(P21.x,P21.y, P22.x,P22.y, 0)
|
70
|
+
nc_line(P31.x,P31.y, P32.x,P32.y, 0)
|
71
|
+
nc_line(P41.x,P41.y, P42.x,P42.y, 0)
|
72
|
+
|
73
|
+
create_mesh_se((P12.x+P22.x)/2, (P11.y + P12.y)/2)
|
74
|
+
create_mesh_se((P22.x+P32.x)/2, (P21.y + P22.y)/2)
|
75
|
+
create_mesh_se((P32.x+P42.x)/2, (P31.y + P32.y)/2)
|
76
|
+
|
77
|
+
if (m.yoke_height > 0) then
|
78
|
+
nc_line(P13.x,P13.y, P43.x,P43.y, 0)
|
79
|
+
nc_line(P12.x,P12.y, P13.x,P13.y, 0)
|
80
|
+
nc_line(P42.x,P42.y, P43.x,P43.y, 0)
|
81
|
+
x,y = (P12.x+P42.x)/2,(P42.y+P43.y)/2
|
82
|
+
create_mesh_se(x,y)
|
83
|
+
def_new_sreg(x,y, "rofe", "blue")
|
84
|
+
if (mcvkey_yoke == 'dummy') then
|
85
|
+
def_mat_fm(x,y, blue, 1000, 100)
|
86
|
+
else
|
87
|
+
def_mat_fm_nlin(x,y, blue, mcvkey_yoke, 100, 0)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
translate_copy_nodechains(P11.x,P11.y, P13.x,P13.y, P43.x,P43.y, P41.x,P41.y, m.npols_gen-1)
|
92
|
+
|
93
|
+
x = (P12.x+P32.x)/2
|
94
|
+
y = (P12.y+P32.y)/2
|
95
|
+
for i = 1,m.npols_gen do
|
96
|
+
if i%2 == 0 then
|
97
|
+
def_mat_pm(x,y, 'red', m.remanenc, m.relperm, 90, "parallel", 0, m.rlen)
|
98
|
+
else
|
99
|
+
def_mat_pm(x,y, 'green', m.remanenc, m.relperm, 270, "parallel", 0, m.rlen)
|
100
|
+
end
|
101
|
+
x = x + m.pole_width
|
102
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
--[[ Supported AFM Model Types
|
2
|
+
"S1R1" -- 1 stator, 1 rotor
|
3
|
+
"S1R2" -- 1 stator, 2 rotor, 1 half simulated
|
4
|
+
"S1R2_all" -- 1 stator, 2 rotor, all simulated
|
5
|
+
"S2R1" -- 2 stator, 1 rotor, 1 half simulated
|
6
|
+
"S2R1_all" -- 2 stator, 1 rotor, all simulated
|
7
|
+
b--]]
|
8
|
+
m.slot_height = ${model['slot_height']*1e3} -- Total slot height [mm]
|
9
|
+
m.slot_h1 = ${model['slot_h1']*1e3} -- Slot opening height [mm]
|
10
|
+
m.slot_h2 = ${model['slot_h2']*1e3} -- Distance to radius [mm]
|
11
|
+
m.st_yoke_height = ${model['yoke_height']*1e3} -- Yoke height [mm]
|
12
|
+
m.slot_width = ${model['slot_width']*1e3} -- Slot width [mm]
|
13
|
+
m.slot_open_width = ${model['slot_open_width']*1e3} -- Slot opening width [mm]
|
14
|
+
m.slot_r1 = ${model['slot_r1']*1e3} -- Slot radius [mm]
|
15
|
+
m.slot_r2 = ${model['slot_r2']*1e3} -- Slot radius [mm]
|
16
|
+
m.mcvkey_yoke = mcvkey_yoke
|
17
|
+
m.nodedist = ${model.get('m.nodedist', 1)} -- Node distance
|
18
|
+
|
19
|
+
if (m.model_type == "S1R2") or (m.model_type == "S1R2_all") then
|
20
|
+
if (m.st_yoke_height > 0) then
|
21
|
+
m.st_yoke_height = 0
|
22
|
+
print("Warning: m.st_yoke_height for this type must be 0. Set to 0!")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
if m.st_yoke_height > 0 then
|
27
|
+
sh = m.slot_height
|
28
|
+
else
|
29
|
+
sh = m.slot_height/2
|
30
|
+
end
|
31
|
+
|
32
|
+
fml = require("fml")
|
33
|
+
|
34
|
+
P0 = fml.Point:Create(0,0)
|
35
|
+
|
36
|
+
Lh1 = fml.Line:Create(P0,0)
|
37
|
+
Lh2 = fml.Line:Parallel(Lh1,-m.slot_h1)
|
38
|
+
Lh3 = fml.Line:Parallel(Lh1,-m.slot_h2)
|
39
|
+
Lh4 = fml.Line:Parallel(Lh1,-(sh-m.slot_r2))
|
40
|
+
Lh5 = fml.Line:Parallel(Lh1,-sh)
|
41
|
+
Lh6 = fml.Line:Parallel(Lh1,-(sh+m.st_yoke_height))
|
42
|
+
|
43
|
+
Lv1 = fml.Line:Create(P0,90)
|
44
|
+
m.width_bz = m.pole_width*m.num_poles/m.tot_num_slot
|
45
|
+
m.tooth_width = m.width_bz-m.slot_width
|
46
|
+
Lv2 = fml.Line:Parallel(Lv1,m.tooth_width/2)
|
47
|
+
Lv3 = fml.Line:Parallel(Lv1,m.tooth_width/2+m.slot_r1)
|
48
|
+
Lv4 = fml.Line:Parallel(Lv1,m.tooth_width/2+m.slot_r2)
|
49
|
+
Lv5 = fml.Line:Parallel(Lv1,m.tooth_width/2+m.slot_width/2-m.slot_open_width/2)
|
50
|
+
Lv6 = fml.Line:Parallel(Lv1,m.tooth_width/2+m.slot_width/2)
|
51
|
+
|
52
|
+
P11 = P0
|
53
|
+
P16 = fml.Point:Intersection(Lh6,Lv1)
|
54
|
+
P23 = fml.Point:Intersection(Lh3,Lv2)
|
55
|
+
P24 = fml.Point:Intersection(Lh4,Lv2)
|
56
|
+
P25 = fml.Point:Intersection(Lh5,Lv2)
|
57
|
+
P26 = fml.Point:Intersection(Lh6,Lv2)
|
58
|
+
P34 = fml.Point:Intersection(Lh4,Lv3)
|
59
|
+
P33 = fml.Point:Intersection(Lh3,Lv3)
|
60
|
+
P44 = fml.Point:Intersection(Lh4,Lv4)
|
61
|
+
P45 = fml.Point:Intersection(Lh5,Lv4)
|
62
|
+
P51 = fml.Point:Intersection(Lh1,Lv5)
|
63
|
+
P52 = fml.Point:Intersection(Lh2,Lv5)
|
64
|
+
P61 = fml.Point:Intersection(Lh1,Lv6)
|
65
|
+
P62 = fml.Point:Intersection(Lh2,Lv6)
|
66
|
+
P65 = fml.Point:Intersection(Lh5,Lv6)
|
67
|
+
P66 = fml.Point:Intersection(Lh6,Lv6)
|
68
|
+
|
69
|
+
if (m.slot_r1 > 0) then
|
70
|
+
C1 = fml.Circle:Create(P33,m.slot_r1)
|
71
|
+
P32 = fml.Point:Tangent(P52,C1,2)
|
72
|
+
else
|
73
|
+
P32 = P23
|
74
|
+
end
|
75
|
+
|
76
|
+
model_size = m.pole_width*m.num_poles*m.num_slots/m.tot_num_slot
|
77
|
+
blow_up_wind(0,-model_size/2, model_size,model_size/2)
|
78
|
+
ndt(m.nodedist)
|
79
|
+
|
80
|
+
nc_line(P11.x,P11.y, P52.x,P51.y, 0)
|
81
|
+
nc_line_cont(P61.x,P61.y, 0)
|
82
|
+
nc_line(P52.x,P52.y, P62.x,P62.y, 0)
|
83
|
+
if (m.st_yoke_height > 0) then
|
84
|
+
nc_line(P45.x,P45.y, P65.x,P65.y, 0)
|
85
|
+
nc_line(P16.x,P16.y, P66.x,P66.y, 0)
|
86
|
+
else
|
87
|
+
nc_line(P16.x,P16.y, P26.x,P26.y, 0)
|
88
|
+
nc_line_cont(P66.x,P66.y, 0)
|
89
|
+
end
|
90
|
+
|
91
|
+
nc_line(P11.x,P11.y, P16.x,P16.y, 0)
|
92
|
+
if (m.st_yoke_height > 0) then
|
93
|
+
nc_line(P23.x,P23.y, P24.x,P24.y, 0)
|
94
|
+
else
|
95
|
+
nc_line(P23.x,P23.y, P26.x,P26.y, 0)
|
96
|
+
end
|
97
|
+
nc_line(P51.x,P51.y, P52.x,P52.y, 0)
|
98
|
+
nc_line(P61.x,P61.y, P62.x,P62.y, 0)
|
99
|
+
if (m.st_yoke_height > 0) then
|
100
|
+
nc_line_cont(P65.x,P65.y, 0)
|
101
|
+
nc_line_cont(P66.x,P66.y, 0)
|
102
|
+
else
|
103
|
+
nc_line_cont(P66.x,P66.y, 0)
|
104
|
+
end
|
105
|
+
nc_line(P52.x,P52.y, P32.x,P32.y, 0)
|
106
|
+
|
107
|
+
if (m.slot_r1 > 0) then
|
108
|
+
nc_circle_m(P23.x,P23.y, P32.x,P32.y, P33.x,P33.y, m.slot_r1, 0)
|
109
|
+
end
|
110
|
+
if (m.st_yoke_height > 0 and m.slot_r2 > 0) then
|
111
|
+
nc_circle_m(P45.x,P45.y, P24.x,P24.y, P44.x,P44.y, m.slot_r2, 0)
|
112
|
+
end
|
113
|
+
|
114
|
+
if m.slot_h1 > 0 then
|
115
|
+
create_mesh_se((P51.x+P61.x)/2, (P51.y + P52.y)/2)
|
116
|
+
end
|
117
|
+
create_mesh_se((P23.x+P62.x)/2, (P62.y + P65.y)/2)
|
118
|
+
|
119
|
+
x,y = (P11.x+P26.x)/2,(P11.y+P26.y)/2
|
120
|
+
create_mesh_se(x, y)
|
121
|
+
def_new_sreg(x,y, "stfe", "blue")
|
122
|
+
|
123
|
+
x1,y1 = P61.x,P61.y
|
124
|
+
x2,y2 = P66.x,P66.y
|
125
|
+
mirror_nodechains(x1,y1, x2,y2)
|
126
|
+
|
127
|
+
x1,y1 = P16.x,P16.y
|
128
|
+
x2,y2 = P11.x,P11.y
|
129
|
+
x3,y3 = 2*P61.x,P61.y
|
130
|
+
x4,y4 = 2*P61.x,P66.y
|
131
|
+
translate_copy_nodechains(x1,y1, x2,y2, x3,y3, x4,y4,
|
132
|
+
m.num_sl_gen-1)
|
133
|
+
|
134
|
+
x,y = (P11.x+P26.x)/2,(P11.y+P26.y)/2
|
135
|
+
if (m.mcvkey_yoke == 'dummy') then
|
136
|
+
def_mat_fm(x,y, blue, 1000, 100)
|
137
|
+
else
|
138
|
+
def_mat_fm_nlin(x,y, blue, m.mcvkey_yoke, 100, 0)
|
139
|
+
end
|
140
|
+
|
141
|
+
m.middle_line = 1 -- vertical slot parts
|