63 if (sampleRate <= 0.0)
return;
64 invFs2_ = 0.5 / sampleRate;
65 fs2_ = 2.0 * sampleRate;
89 void setParameters(
double ms,
double a,
double alpha,
double k,
double c)
noexcept
91 ms_ = std::max(ms, 1.0);
92 a_ = std::max(a, 1.0);
93 alpha_ = std::max(alpha, 0.0);
94 k_ = std::max(k, 1.0);
95 c_ = std::clamp(c, 0.0, 0.999);
110 const double chiAn = ms_ / (3.0 * a_);
111 return c_ * chiAn / (1.0 - c_ * alpha_ * chiAn);
125 if (!std::isfinite(fieldH))
return static_cast<T
>(m_);
127 const double h =
static_cast<double>(fieldH);
128 const double hDot = fs2_ * (h - hPrev_) - hDotPrev_;
131 double m = m_ + 2.0 * invFs2_ * wPrev_;
132 const double rhs = m_ + invFs2_ * wPrev_;
134 double w = 0.0, dwdm = 0.0;
135 for (
int it = 0; it < 4; ++it)
137 evaluate(m, h, hDot, w, dwdm);
138 const double g = m - rhs - invFs2_ * w;
139 const double gp = 1.0 - invFs2_ * dwdm;
140 const double dm = g / gp;
142 if (std::abs(dm) < 1e-9 * ms_)
146 m = std::clamp(m, -ms_, ms_);
148 evaluate(m, h, hDot, w, dwdm);
153 return static_cast<T
>(m);
158 static void langevin(
double x,
double& l,
double& lp,
double& lpp)
noexcept
160 const double ax = std::abs(x);
164 const double x2 = x * x;
165 l = x * (1.0 / 3.0 - x2 / 45.0);
166 lp = 1.0 / 3.0 - x2 / 15.0;
167 lpp = -2.0 * x / 15.0;
172 l = (x > 0.0 ? 1.0 : -1.0) - 1.0 / x;
174 lpp = -2.0 / (x * x * x);
178 const double e = std::exp(x);
179 const double ie = 1.0 / e;
180 const double sh = 0.5 * (e - ie);
181 const double ch = 0.5 * (e + ie);
182 const double coth = ch / sh;
183 const double csch2 = 1.0 / (sh * sh);
184 const double ix = 1.0 / x;
186 lp = ix * ix - csch2;
187 lpp = 2.0 * (csch2 * coth - ix * ix * ix);
192 void evaluate(
double m,
double h,
double hDot,
double& w,
double& dwdm)
const noexcept
201 const double q = (h + alpha_ * m) / a_;
202 double l = 0.0, lp = 0.0, lpp = 0.0;
203 langevin(q, l, lp, lpp);
205 const double mAn = ms_ * l;
206 const double dM = mAn - m;
207 const double delta = (hDot > 0.0) ? 1.0 : -1.0;
208 const double deltaM = (dM * delta > 0.0) ? 1.0 : 0.0;
211 const double oneMc = 1.0 - c_;
212 double d1 = oneMc * delta * k_ - alpha_ * dM;
213 const double d1Min = 0.01 * oneMc * k_;
214 if (std::abs(d1) < d1Min)
215 d1 = (d1 >= 0.0) ? d1Min : -d1Min;
217 const double phi1 = oneMc * deltaM * dM / d1;
218 const double cChiLp = c_ * chi_ * lp;
220 const double num = phi1 + cChiLp;
226 double den = 1.0 - alpha_ * cChiLp;
227 if (std::abs(den) < 0.01)
228 den = (den >= 0.0) ? 0.01 : -0.01;
229 w = hDot * num / den;
232 const double alphaOverA = alpha_ / a_;
233 const double dmAn = ms_ * lp * alphaOverA - 1.0;
234 const double dPhi1 = oneMc * deltaM * dmAn * (oneMc * delta * k_) / (d1 * d1);
235 const double dLp = lpp * alphaOverA;
236 const double dNum = dPhi1 + c_ * chi_ * dLp;
237 const double dDen = -alpha_ * c_ * chi_ * dLp;
238 dwdm = hDot * (dNum * den - num * dDen) / (den * den);
242 double ms_ = 3.5e5, a_ = 2.2e4, alpha_ = 1.6e-3, k_ = 2.7e4, c_ = 1.7e-1;
243 double chi_ = 3.5e5 / 2.2e4;
245 double invFs2_ = 0.5 / 48000.0;
246 double fs2_ = 2.0 * 48000.0;
250 double hDotPrev_ = 0.0;
void setParameters(double ms, double a, double alpha, double k, double c) noexcept
Sets the Jiles-Atherton parameters.