Constant/static overlayed field (i.e. earth magnetic field) #680
-
First of all, very nice library, well done! I have a set of magnets and magnet sensors and want to overlay the earth magnetic field (i.e. a constant homogenious field). Is there any easy way to do that ? BR, |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 3 replies
-
Hi @BastelBaus, Thanks for the kind words, happy to see that you appreciate our work ;) There is a special object type Important Be aware that changing the object orientation will also affect the orientation of the produced field, since the field function output is always considered as local. The Magpylib library makes the necessary coordinates transformations on its own when calling The straightforward wayYou can create a CustomSource object directly and define a custom field function like below. import magpylib as magpy
import numpy as np
# Define a custom field function
def earth_field_func(field, observers):
observers = np.asarray(observers)
earth_mag = 0.05 # for earth magnetic field in mT
# by default points in x-direction
return np.repeat([[earth_mag, 0, 0]], len(observers), axis=0)
# Create custom source
earth_field = magpy.misc.CustomSource(
field_func=earth_field_func,
style_label="Earth magnetic field",
)
# Usage for earth field in x
earth_field.getB([1, 2, 3]) # for an observer
# -> array([0.05, 0. , 0. ])
# Usage for earth field in y
earth_field.rotate_from_angax(90, "z")
earth_field.getB([[1, 2, 3],[4,5,6]]).round(6)
# -> array([[-0. , -0.05, 0. ],
# [-0. , -0.05, 0. ]]) The more generalized wayA more advanced way to do it, would be to subclass the original import numbers
import magpylib as magpy
import numpy as np
class HomogeneousField(magpy.misc.CustomSource):
def __init__(self, field_magnitude, field_axis="x", **kwargs):
"""
Defines a Homogeneous uniform field.
Can be used to define a local earth magnetic field influence.
Parameters
----------
field_magnitude: scalar
Field magnitude in mT.
field_axis: str or array_like, shape (3,)
The direction of the magnetic field in the local coordinate system.
Input can be a vector of shape (3,) or a string 'x', 'y' or 'z' to
denote respective directions. Vector length is ignored as the magnitude
is set seperately by the `field_magnitude` parameter.
"""
super().__init__(**kwargs)
self._field_magnitude = None
self._field_axis = None
self.field_magnitude = field_magnitude
self.field_axis = field_axis
@property
def field_magnitude(self):
return self._field_magnitude
@field_magnitude.setter
def field_magnitude(self, val):
if not isinstance(val, numbers.Number):
raise ValueError(
f"The `field_magnitude` parameter of {self.__class__.__name__} "
f"must be a number. Received {val!r} instead."
)
self._field_magnitude = float(val)
self._update_field_func()
@property
def field_axis(self):
return self._field_axis
@field_axis.setter
def field_axis(self, val):
passed = True
if isinstance(val, str) and val in "xyz":
arr = [0, 0, 0]
arr["xyz".index(val)] = 1
val = np.array(arr, dtype=float)
elif isinstance(val, (list, tuple, np.ndarray)):
val = np.asarray(val, dtype=float)
if val.shape != (3,) or all(v == 0 for v in val):
passed = False
else:
passed = False
if not passed:
raise ValueError(
f"The `field_axis` parameter of {self.__class__.__name__} "
"must be a vector of shape (3,) or a string 'x', 'y' or 'z' to "
f"denote respective directions. Received {val!r} instead."
)
self._field_axis = val
self._update_field_func()
def _update_field_func(self):
if self._field_magnitude is None or self._field_axis is None:
return # wait for both attributes to be set
axis = self._field_axis
axis /= np.linalg.norm(axis)
field_val = self._field_magnitude * axis
def field_func(field, observers):
observers = np.asarray(observers)
return np.repeat([field_val], len(observers), axis=0)
self.field_func = field_func Optionally you can add the following methods to the class definition above. If you want to "freeze" your objects. We may implement a much simpler way to do it in future releases of the library. # prevent moving and rotating object by mistake (optional)
def move(self, *args, **kwargs):
raise Exception(f"{self.__class__.__name__} is not supposed to be moved")
def rotate(self, *args, **kwargs):
raise Exception(f"{self.__class__.__name__} is not supposed to be rotated")
@property
def position(self):
return self._position
@position.setter
def position(self, _):
raise Exception(f"{self.__class__.__name__} is not supposed to be moved")
@property
def orientation(self):
return self._orientation
@orientation.setter
def orientation(self, _):
raise Exception(f"{self.__class__.__name__} is not supposed to be rotated") Hope this helps, Best regards - Alex |
Beta Was this translation helpful? Give feedback.
Hi @BastelBaus,
Thanks for the kind words, happy to see that you appreciate our work ;)
There is a special object type
CustomSource
that allows to do exactly what you are looking for! ACustomSource
object behaves like any other object of the library and can be positioned, rotated, be part ofCollection
and called in agetB
/getH
context.Important
Be aware that changing the object orientation will also affect the orientation of the produced field, since the field function output is always considered as local. The Magpylib library makes the necessary coordinates transformations on its own when calling
getB
/getH
.The straightforward way
You can create a CustomSource object directly and def…