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.
@@ -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
- pts = self.geom.split_and_get_intersect_points(self.center,
722
- self.radius+10,
723
- midangle)
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], hm, 0)
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.el_fe_induction_1[0][0].append(self.next_block("h"))
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.el_fe_induction_1[1][0].append(self.next_block("h"))
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.el_fe_induction_1[2][0].append(self.next_block("h"))
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
- logger.debug(reader.el_fe_induction_1)
692
- if len(np.asarray(reader.el_fe_induction_1).shape) > 2:
693
- self.el_fe_induction_1 = np.asarray(
694
- reader.el_fe_induction_1).T/1000
695
- self.el_fe_induction_2 = np.asarray(
696
- reader.el_fe_induction_2).T/1000
697
- self.eddy_cu_vpot = np.asarray(reader.eddy_cu_vpot).T/1000
698
- else:
699
- try:
700
- self.el_fe_induction_1 = np.asarray(
701
- [e for e in reader.el_fe_induction_1 if e[0]]).T/1000
702
- self.el_fe_induction_2 = np.asarray(
703
- [e for e in reader.el_fe_induction_2 if e[0]]).T/1000
704
- self.eddy_cu_vpot = np.asarray(
705
- [e for e in reader.eddy_cu_vpot if e[0]]).T/1000
706
- logger.debug('El Fe Induction %s', np.asarray(
707
- reader.el_fe_induction_1).shape)
708
- except:
709
- pass
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', [])
@@ -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
- tfric = eecpars['kfric_b']*eecpars['rotor_mass']*30e-3/np.pi
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
 
@@ -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
- yd = machine['windings'].get('coil_span', Q1/machine['poles'])
372
- wdg = windings.Winding(
373
- {'Q': machine['stator']['num_slots'],
374
- 'm': machine['windings']['num_phases'],
375
- 'p': machine['poles']//2,
376
- 'l': machine['windings']['num_layers'],
377
- 'yd': yd})
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
- ax.set_title('Torque / {}'.format(unit))
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 for s in sr for sre in isa.get_subregion(s).elements()
1348
- for e in sre]
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
- norm = 10**(np.ceil(np.log10(np.max(np.abs(v)))))
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