femagtools 1.3.0__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 +148 -13
- femagtools/bch.py +19 -3
- femagtools/dxfsl/area.py +68 -15
- femagtools/dxfsl/converter.py +15 -6
- femagtools/dxfsl/fslrenderer.py +13 -8
- femagtools/dxfsl/functions.py +1 -1
- femagtools/dxfsl/geom.py +415 -62
- femagtools/dxfsl/machine.py +97 -5
- femagtools/dxfsl/shape.py +46 -2
- femagtools/ecloss.py +393 -0
- femagtools/femag.py +25 -1
- femagtools/fsl.py +3 -2
- femagtools/hxy.py +126 -0
- femagtools/isa7.py +37 -24
- femagtools/machine/__init__.py +14 -13
- femagtools/machine/effloss.py +153 -32
- femagtools/machine/im.py +137 -56
- femagtools/machine/pm.py +584 -202
- femagtools/machine/sm.py +218 -64
- femagtools/machine/utils.py +12 -8
- femagtools/mcv.py +6 -8
- femagtools/model.py +11 -1
- femagtools/parstudy.py +1 -1
- femagtools/plot.py +159 -35
- femagtools/templates/afm_rotor.mako +102 -0
- femagtools/templates/afm_stator.mako +141 -0
- femagtools/templates/airgapinduc.mako +3 -3
- 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-dynamic.mako +12 -6
- 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.0.dist-info → femagtools-1.3.2.dist-info}/METADATA +1 -1
- {femagtools-1.3.0.dist-info → femagtools-1.3.2.dist-info}/RECORD +47 -41
- {femagtools-1.3.0.dist-info → femagtools-1.3.2.dist-info}/WHEEL +1 -1
- {femagtools-1.3.0.dist-info → femagtools-1.3.2.dist-info}/LICENSE +0 -0
- {femagtools-1.3.0.dist-info → femagtools-1.3.2.dist-info}/entry_points.txt +0 -0
- {femagtools-1.3.0.dist-info → femagtools-1.3.2.dist-info}/top_level.txt +0 -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))
|
@@ -896,7 +899,34 @@ def transientsc(bch, title=''):
|
|
896
899
|
fig.tight_layout(h_pad=2)
|
897
900
|
if title:
|
898
901
|
fig.subplots_adjust(top=0.92)
|
902
|
+
return fig
|
899
903
|
|
904
|
+
def transientsc_demag(demag, magnet=0, title='', ax=0):
|
905
|
+
"""creates a demag plot of a transient short circuit
|
906
|
+
Args:
|
907
|
+
demag: list of dicts with 'displ', 'H_av', 'H_max', 'lim_hc'
|
908
|
+
magnet dict with 'Tmag'
|
909
|
+
"""
|
910
|
+
if ax == 0:
|
911
|
+
ax = plt.gca()
|
912
|
+
pos = [d['displ'] for d in demag if 'displ' in d]
|
913
|
+
hmax = [-d['H_max'] for d in demag if 'H_max' in d]
|
914
|
+
havg = [-d['H_av'] for d in demag if 'H_av' in d]
|
915
|
+
hclim = [-d['lim_hc'] for d in demag if 'lim_hc' in d]*2
|
916
|
+
|
917
|
+
ax.set_title('Transient Short Circuit Demagnetization [kA/m]')
|
918
|
+
ax.plot(pos, hmax,
|
919
|
+
label='H Max {:4.2f} kA/m'.format(max(hmax)))
|
920
|
+
ax.plot(pos, havg,
|
921
|
+
label='H Avg {:4.2f} kA/m'.format(max(havg)))
|
922
|
+
ax.plot([pos[0], pos[-1]], hclim, color='C3', linestyle='dashed',
|
923
|
+
label='Hc {:4.2f} kA/m'.format(hclim[0]))
|
924
|
+
ax.set_xlabel('Rotor Position / °')
|
925
|
+
ax.grid(True)
|
926
|
+
if magnet:
|
927
|
+
ax.legend(title=f"Magnet Temperature {magnet['Tmag']}°C")
|
928
|
+
else:
|
929
|
+
ax.legend()
|
900
930
|
|
901
931
|
def i1beta_torque(i1, beta, torque, title='', ax=0):
|
902
932
|
"""creates a surface plot of torque vs i1, beta"""
|
@@ -1222,7 +1252,7 @@ def _contour(ax, title, elements, values, label='', isa=None):
|
|
1222
1252
|
if ax == 0:
|
1223
1253
|
ax = plt.gca()
|
1224
1254
|
ax.set_aspect('equal')
|
1225
|
-
ax.set_title(title
|
1255
|
+
ax.set_title(title)
|
1226
1256
|
if isa:
|
1227
1257
|
for se in isa.superelements:
|
1228
1258
|
ax.add_patch(Polygon([n.xy
|
@@ -1236,13 +1266,13 @@ def _contour(ax, title, elements, values, label='', isa=None):
|
|
1236
1266
|
p = PatchCollection(patches, alpha=1.0, match_original=False)
|
1237
1267
|
p.set_array(np.asarray(values)[valid_values])
|
1238
1268
|
ax.add_collection(p)
|
1239
|
-
cb = plt.colorbar(p)
|
1269
|
+
cb = plt.colorbar(p, shrink=0.9)
|
1240
1270
|
for patch in np.array([Polygon([v.xy for v in e.vertices],
|
1241
1271
|
fc='white', alpha=1.0)
|
1242
1272
|
for e in elements])[np.isnan(values)]:
|
1243
1273
|
ax.add_patch(patch)
|
1244
1274
|
if label:
|
1245
|
-
cb.set_label(label=label
|
1275
|
+
cb.set_label(label=label)
|
1246
1276
|
ax.autoscale(enable=True)
|
1247
1277
|
ax.axis('off')
|
1248
1278
|
|
@@ -1254,29 +1284,35 @@ def demag(isa, ax=0):
|
|
1254
1284
|
"""
|
1255
1285
|
emag = [e for e in isa.elements if e.is_magnet()]
|
1256
1286
|
demag = np.array([e.demagnetization(isa.MAGN_TEMPERATURE) for e in emag])
|
1257
|
-
_contour(ax, f'Demagnetization at {isa.MAGN_TEMPERATURE} °C',
|
1287
|
+
_contour(ax, f'Demagnetization at {isa.MAGN_TEMPERATURE} °C (max -{np.max(demag):.1f} kA/m)',
|
1258
1288
|
emag, demag, '-H / kA/m', isa)
|
1259
1289
|
logger.info("Max demagnetization %f", np.max(demag))
|
1260
1290
|
|
1261
1291
|
|
1262
|
-
def demag_pos(isa, pos, icur=-1, ibeta=-1, ax=0):
|
1292
|
+
def demag_pos(isa, pos=-1, icur=-1, ibeta=-1, ax=0):
|
1263
1293
|
"""plot demag of NC/I7/ISA7 model at rotor position
|
1264
1294
|
Args:
|
1265
1295
|
isa: Isa7/NC object
|
1266
|
-
pos: rotor position in degree
|
1296
|
+
pos: rotor position in degree (maximum h if -1)
|
1267
1297
|
icur: cur amplitude index or last index if -1
|
1268
1298
|
ibeta: beta angle index or last index if -1
|
1269
1299
|
"""
|
1270
1300
|
emag = [e for e in isa.elements if e.is_magnet()]
|
1271
1301
|
demag = np.array([isa.demagnetization(e, icur, ibeta)[1]
|
1272
1302
|
for e in emag])
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1303
|
+
if pos>=0:
|
1304
|
+
for i, x in enumerate(isa.pos_el_fe_induction):
|
1305
|
+
if x >= pos/180*np.pi:
|
1306
|
+
break
|
1307
|
+
else:
|
1308
|
+
demagmax = np.max(demag, axis=0)
|
1309
|
+
i = np.argmax(demagmax)
|
1310
|
+
x = isa.pos_el_fe_induction[i]
|
1276
1311
|
|
1277
1312
|
hpol = demag[:, i]
|
1278
1313
|
hpol[hpol == 0] = np.nan
|
1279
|
-
_contour(ax, f'Demagnetization at
|
1314
|
+
_contour(ax, f'Demagnetization at pos. {round(x/np.pi*180):.1f}°,'
|
1315
|
+
f'{isa.MAGN_TEMPERATURE} °C (max -{np.max(hpol):.1f} kA/m)',
|
1280
1316
|
emag, hpol, '-H / kA/m', isa)
|
1281
1317
|
logger.info("Max demagnetization %f kA/m", np.nanmax(hpol))
|
1282
1318
|
|
@@ -1297,7 +1333,7 @@ def flux_density(isa, subreg=[], ax=0):
|
|
1297
1333
|
elements = [e for e in isa.elements]
|
1298
1334
|
|
1299
1335
|
fluxd = np.array([np.linalg.norm(e.flux_density()) for e in elements])
|
1300
|
-
_contour(ax, f'Flux Density T', elements, fluxd)
|
1336
|
+
_contour(ax, f'Flux Density T (max {np.max(fluxd):.1f} T)', elements, fluxd)
|
1301
1337
|
logger.info("Max flux dens %f", np.max(fluxd))
|
1302
1338
|
|
1303
1339
|
|
@@ -1311,8 +1347,9 @@ def loss_density(isa, subreg=[], ax=0):
|
|
1311
1347
|
sr = subreg
|
1312
1348
|
else:
|
1313
1349
|
sr = [subreg]
|
1314
|
-
elements = [e
|
1315
|
-
for
|
1350
|
+
elements = [e
|
1351
|
+
for s in sr
|
1352
|
+
for e in isa.get_subregion(s).elements()]
|
1316
1353
|
else:
|
1317
1354
|
elements = [e for e in isa.elements]
|
1318
1355
|
|
@@ -1652,15 +1689,26 @@ def characteristics(char, title=''):
|
|
1652
1689
|
fig.suptitle(title)
|
1653
1690
|
|
1654
1691
|
n = np.array(char['n'])*60
|
1655
|
-
|
1692
|
+
punit = 'kW'
|
1693
|
+
k = 1e-3
|
1694
|
+
if max(char['pmech']) > 1e6:
|
1695
|
+
punit = 'MW'
|
1696
|
+
k = 1e-6
|
1697
|
+
pmech = np.array(char['pmech'])*k
|
1698
|
+
tunit = 'Nm'
|
1699
|
+
if max(char['T']) > 1e3:
|
1700
|
+
tunit = 'kNm'
|
1701
|
+
tq = np.array(char['T'])*1e-3
|
1702
|
+
else:
|
1703
|
+
tq = np.array(char['T'])
|
1656
1704
|
|
1657
|
-
axs[0, 0].plot(n,
|
1658
|
-
axs[0, 0].set_ylabel("Torque /
|
1705
|
+
axs[0, 0].plot(n, tq, 'C0-', label='Torque')
|
1706
|
+
axs[0, 0].set_ylabel(f"Torque / {tunit}")
|
1659
1707
|
axs[0, 0].grid()
|
1660
1708
|
axs[0, 0].legend(loc='center left')
|
1661
1709
|
ax1 = axs[0, 0].twinx()
|
1662
1710
|
ax1.plot(n, pmech, 'C1-', label='P mech')
|
1663
|
-
ax1.set_ylabel("Power /
|
1711
|
+
ax1.set_ylabel(f"Power / {punit}")
|
1664
1712
|
ax1.legend(loc='lower center')
|
1665
1713
|
|
1666
1714
|
axs[0, 1].plot(n[1:], np.array(char['u1'][1:]), 'C0-', label='Voltage')
|
@@ -1697,6 +1745,12 @@ def characteristics(char, title=''):
|
|
1697
1745
|
pl = np.array(char['losses'])*1e-3
|
1698
1746
|
axs[1, 1].plot(n, plcu, 'C0-', label='Cu Losses')
|
1699
1747
|
axs[1, 1].plot(n, plfe, 'C1-', label='Fe Losses')
|
1748
|
+
try:
|
1749
|
+
if char['plfw'] and char['plfw'][-1] > 0:
|
1750
|
+
plfw = np.array(char['plfw'])*1e-3
|
1751
|
+
axs[1, 1].plot(n, plfw, 'C2-', label='Friction + Windage')
|
1752
|
+
except KeyError:
|
1753
|
+
pass
|
1700
1754
|
axs[1, 1].set_ylabel("Losses / kW")
|
1701
1755
|
axs[1, 1].legend(loc='center left')
|
1702
1756
|
axs[1, 1].grid()
|
@@ -1724,12 +1778,62 @@ def get_nT_boundary(n, T):
|
|
1724
1778
|
bnd[1].append((nx, tx))
|
1725
1779
|
return np.array(bnd[0] + bnd[1][::-1])
|
1726
1780
|
|
1781
|
+
def normalize10(v, **kwargs):
|
1782
|
+
"""
|
1783
|
+
Normalizes the input-array using the nearest (ceiling) power of 10.
|
1784
|
+
|
1785
|
+
Arguments:
|
1786
|
+
v: array to normalize
|
1727
1787
|
|
1728
|
-
|
1788
|
+
Returns:
|
1789
|
+
normalized array
|
1790
|
+
normalisation factor (power of 10)
|
1791
|
+
"""
|
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))))
|
1813
|
+
return v / norm, norm
|
1814
|
+
|
1815
|
+
|
1816
|
+
def plot_contour(speed, torque, z, ax, title='', levels=[],
|
1817
|
+
clabel=True, cmap='YlOrRd', cbar=False, **kwargs):
|
1818
|
+
""" contour plot of speed, torque, z values
|
1819
|
+
Arguments:
|
1820
|
+
levels: (list of floats)
|
1821
|
+
clabel: contour labels if True
|
1822
|
+
cmap: colour map
|
1823
|
+
cbar: (bool) create color bar if True (default False)
|
1824
|
+
|
1825
|
+
Note: the x and y axes are scaled
|
1826
|
+
|
1827
|
+
returns tricontourf, xscale, yscale
|
1828
|
+
"""
|
1729
1829
|
from matplotlib.path import Path
|
1730
1830
|
from matplotlib.patches import PathPatch
|
1731
|
-
x =
|
1732
|
-
y = torque
|
1831
|
+
x = 60*np.asarray(speed)
|
1832
|
+
y = np.asarray(torque)
|
1833
|
+
|
1834
|
+
x, xscale = normalize10(x, **kwargs)
|
1835
|
+
y, yscale = normalize10(y, **kwargs)
|
1836
|
+
|
1733
1837
|
if not levels:
|
1734
1838
|
if max(z) <= 1:
|
1735
1839
|
if max(z) > 0.96:
|
@@ -1743,38 +1847,58 @@ def plot_contour(speed, torque, z, ax, title='', levels=[], clabel=True):
|
|
1743
1847
|
levels.append(np.ceil(max(z)*100)/100)
|
1744
1848
|
else:
|
1745
1849
|
levels = 14
|
1746
|
-
cont = ax.tricontour(x, y, z,
|
1747
|
-
linewidths=0.4, levels=levels, colors='k')
|
1748
|
-
if clabel:
|
1749
|
-
ax.clabel(cont, inline=True, colors='k', fontsize=8)
|
1750
|
-
contf = ax.tricontourf(x, y, z,
|
1751
|
-
levels=levels, cmap='YlOrRd')
|
1752
1850
|
#
|
1753
1851
|
ax.spines['top'].set_color('none')
|
1754
1852
|
ax.spines['right'].set_color('none')
|
1755
1853
|
|
1854
|
+
cont = ax.tricontour(x, y, z,
|
1855
|
+
linewidths=0.4, levels=levels,
|
1856
|
+
colors='k')
|
1857
|
+
contf = ax.tricontourf(x, y, z,
|
1858
|
+
levels=levels, cmap=cmap)
|
1859
|
+
|
1756
1860
|
clippath = Path(get_nT_boundary(x, y))
|
1757
1861
|
patch = PathPatch(clippath, facecolor='none')
|
1758
1862
|
ax.add_patch(patch)
|
1759
1863
|
for c in cont.collections:
|
1760
1864
|
c.set_clip_path(patch)
|
1865
|
+
#ax.plot(x, y, "k.", ms=3)
|
1866
|
+
if clabel:
|
1867
|
+
ax.clabel(cont, inline=True, colors='k', fontsize=8, inline_spacing=0)
|
1868
|
+
|
1761
1869
|
for c in contf.collections:
|
1762
1870
|
c.set_clip_path(patch)
|
1763
|
-
|
1871
|
+
|
1872
|
+
if xscale > 1:
|
1873
|
+
def format_fn(tick_val, tick_pos):
|
1874
|
+
return round(xscale*tick_val)
|
1875
|
+
ax.xaxis.set_major_formatter(format_fn)
|
1876
|
+
if yscale > 1:
|
1877
|
+
def format_fn(tick_val, tick_pos):
|
1878
|
+
return round(yscale*tick_val)
|
1879
|
+
ax.yaxis.set_major_formatter(format_fn)
|
1880
|
+
|
1764
1881
|
ax.set_ylabel('Torque / Nm')
|
1765
1882
|
ax.set_xlabel('Speed / rpm')
|
1766
1883
|
ax.set_title(title)
|
1767
|
-
|
1884
|
+
if cbar:
|
1885
|
+
cfig = ax.get_figure()
|
1886
|
+
cfig.colorbar(contf, ax=ax,
|
1887
|
+
orientation='vertical')
|
1888
|
+
return contf, xscale, yscale
|
1889
|
+
|
1768
1890
|
|
1769
|
-
def efficiency_map(rmap, ax=0, title='Efficiency Map', clabel=True
|
1891
|
+
def efficiency_map(rmap, ax=0, title='Efficiency Map', clabel=True,
|
1892
|
+
cmap='YlOrRd', levels=None, cbar=False):
|
1770
1893
|
if ax == 0:
|
1771
1894
|
fig, ax = plt.subplots(figsize=(12, 12))
|
1772
|
-
|
1773
|
-
|
1774
|
-
|
1895
|
+
return plot_contour(rmap['n'], rmap['T'], rmap['eta'], ax,
|
1896
|
+
title=title, clabel=clabel, cmap=cmap,
|
1897
|
+
levels=levels, cbar=cbar)
|
1775
1898
|
|
1776
1899
|
|
1777
|
-
def losses_map(rmap, ax=0, title='Losses Map / kW', clabel=True
|
1900
|
+
def losses_map(rmap, ax=0, title='Losses Map / kW', clabel=True,
|
1901
|
+
cmap='YlOrRd', cbar=False):
|
1778
1902
|
if ax == 0:
|
1779
1903
|
fig, ax = plt.subplots(figsize=(12, 12))
|
1780
1904
|
return plot_contour(rmap['n'], rmap['T'], np.asarray(rmap['losses'])/1e3, ax,
|
@@ -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
|
@@ -1,6 +1,6 @@
|
|
1
|
-
post_models("induct(x)","
|
1
|
+
post_models("induct(x)","bagx") -- Calculate field distribution
|
2
2
|
data=io.open("bag.dat","w") -- Output in data file
|
3
|
-
for i = 1,
|
4
|
-
data:write(string.format("%g %g %g\n",
|
3
|
+
for i = 1, #bagx, 3 do
|
4
|
+
data:write(string.format("%g %g %g\n",bagx[i],bagx[i+1],bagx[i+2]))
|
5
5
|
end
|
6
6
|
io.close(data)
|
@@ -14,6 +14,7 @@ ag = 0
|
|
14
14
|
% if model.move_action == 0:
|
15
15
|
% if model.external_rotor:
|
16
16
|
dy2 = ${model.get(['outer_diam'])*1e3}
|
17
|
+
% if hasattr(model, 'bore_diam'):
|
17
18
|
% if isinstance(model.get(['bore_diam']), list):
|
18
19
|
<%
|
19
20
|
da2 = '{' + ','.join([str(x*1e3) for x in model.get(['bore_diam'])]) +'}'
|
@@ -27,9 +28,11 @@ end
|
|
27
28
|
da2 = ${model.get(['bore_diam'])*1e3}
|
28
29
|
da1 = da2 - 2*ag
|
29
30
|
% endif
|
31
|
+
% endif # bore_diam dos not exist
|
30
32
|
dy1 = ${model.get(['inner_diam'])*1e3}
|
31
33
|
% else: # internal rotor
|
32
34
|
dy1 = ${model.get(['outer_diam'])*1e3}
|
35
|
+
% if hasattr(model, 'bore_diam'):
|
33
36
|
% if isinstance(model.get(['bore_diam']), list):
|
34
37
|
<%
|
35
38
|
da1 = '{' + ','.join([str(x*1e3) for x in model.get(['bore_diam'])]) +'}'
|
@@ -43,6 +46,7 @@ end
|
|
43
46
|
da1 = ${model.get(['bore_diam'])*1e3}
|
44
47
|
da2 = da1 - 2*ag
|
45
48
|
% endif
|
49
|
+
% endif
|
46
50
|
% if hasattr(model, 'shaft_diam'):
|
47
51
|
dy2 = ${model.get(['shaft_diam'])*1e3}
|
48
52
|
dsh = ${model.get(['inner_diam'])*1e3}
|
@@ -66,7 +70,8 @@ m.num_pol_pair = m.num_poles/2
|
|
66
70
|
m.num_slots = m.num_sl_gen
|
67
71
|
m.npols_gen = m.num_poles * m.num_sl_gen / m.tot_num_slot
|
68
72
|
m.tot_num_sl = m.tot_num_slot
|
69
|
-
% if model.move_action == 0:
|
73
|
+
% if model.move_action == 0: # rotating
|
74
|
+
% if hasattr(model, 'bore_diam'):
|
70
75
|
% if isinstance(model.get(['bore_diam']), list):
|
71
76
|
m.fc_radius = (da1[2]/2-ag[2]/2) -- Radius airgap (extern)
|
72
77
|
m.fc_radius1 = (da1[1]/2-ag[1]/2) -- Radius airgap (intern?)
|
@@ -77,10 +82,26 @@ m.fc_radius1 = m.fc_radius
|
|
77
82
|
m.sl_radius = m.fc_radius -- radius of sliding area
|
78
83
|
% endif
|
79
84
|
% endif
|
85
|
+
% elif hasattr(model, 'pole_width'): # move action linear
|
86
|
+
m.pole_width = ${model['pole_width']*1e3}
|
87
|
+
% endif
|
88
|
+
% if hasattr(model, 'lfe'):
|
80
89
|
m.arm_length = ${model.get(['lfe'])*1e3}
|
90
|
+
% endif
|
81
91
|
pre_models("basic_modpar")
|
82
92
|
% endif
|
83
93
|
% if hasattr(model, 'num_agnodes'):
|
84
|
-
num_agnodes =
|
94
|
+
num_agnodes = m.npols_gen*${model.num_agnodes}
|
95
|
+
% if hasattr(model, 'bore_diam'):
|
85
96
|
agndst = 2*math.pi*m.fc_radius/num_agnodes
|
97
|
+
% else:
|
98
|
+
if m.pole_width ~= nil then
|
99
|
+
agndst = 2*m.pole_width/num_agnodes
|
100
|
+
else
|
101
|
+
agndst = 1 -- last resort
|
102
|
+
end
|
103
|
+
% endif
|
86
104
|
% endif
|
105
|
+
% if hasattr(model, 'afmtype'):
|
106
|
+
m.model_type = "${model['afmtype']}"
|
107
|
+
% endif
|
@@ -1,19 +1,42 @@
|
|
1
1
|
--
|
2
2
|
-- Cogging
|
3
3
|
--
|
4
|
-
m.move_action = 0.0 -- rotate
|
5
4
|
% if model.get('lfe', 0):
|
6
5
|
m.arm_length = ${model.get('lfe')*1e3}
|
7
6
|
% endif
|
8
|
-
|
7
|
+
m.move_action = ${model.get('move_action', 0)}
|
8
|
+
% if model.get('move_action', 0) == 0:
|
9
9
|
m.speed = ${model.get('speed')*60}
|
10
10
|
m.skew_angle = ${model.get('skew_angle', 0)}
|
11
|
+
m.fc_force_points = 0.0 -- number move points in air gap
|
12
|
+
m.phi_start = ${model.get('phi_start', 0)}
|
13
|
+
m.range_phi = ${model.get('range_phi', 0)}
|
14
|
+
% else:
|
15
|
+
m.speed_linear = ${model.get('speed')}
|
16
|
+
m.skew_linear = ${model.get('skew_displ',0)}
|
17
|
+
m.line = 0
|
18
|
+
m.two_pole_wi = 2*m.pole_width
|
19
|
+
m.range_x = m.two_pole_wi
|
20
|
+
m.range_y = 0.0
|
21
|
+
|
22
|
+
m.fc_force_points = 5
|
23
|
+
m.fcpx_mm1 = m.npols_gen*m.pole_width +1.0
|
24
|
+
m.fcpy_mm1 = -ag/2
|
25
|
+
m.fcpx_mm2 = -1.0
|
26
|
+
m.fcpy_mm2 = m.fcpy_mm1
|
27
|
+
m.fcpx_mm3 = m.fcpx_mm2
|
28
|
+
m.fcpy_mm3 = -m.magn_height -m.yoke_height -m.gap_ma_yoke -1 -ag
|
29
|
+
m.fcpx_mm4 = m.fcpx_mm1
|
30
|
+
m.fcpy_mm4 = m.fcpy_mm3
|
31
|
+
m.fcpx_mm5 = m.fcpx_mm1
|
32
|
+
m.fcpy_mm5 = m.fcpy_mm1
|
33
|
+
|
34
|
+
--m.npols_gen = 1 -- number of sectors simulated
|
35
|
+
% endif
|
36
|
+
|
11
37
|
m.nu_skew_steps = ${model.get('num_skew_steps', 0)}
|
12
38
|
m.magn_temp = ${model.get('magn_temp')}
|
13
39
|
m.fc_mult_move_type = 1.0 -- Type of move path in air gap
|
14
|
-
m.fc_force_points = 0.0 -- number move points in air gap
|
15
|
-
m.phi_start = ${model.get('phi_start', 0)}
|
16
|
-
m.range_phi = ${model.get('range_phi', 0)}
|
17
40
|
m.nu_move_steps = ${model.get('num_move_steps', 49)}
|
18
41
|
|
19
42
|
m.num_par_wdgs = ${model.get('num_par_wdgs',1)}
|