65 if (!(sampleRate > 0.0) || !std::isfinite(sampleRate))
return;
66 invFs2_ = 0.5 / sampleRate;
67 fs2_ = 2.0 * sampleRate;
94 void setParameters(
double ms,
double a,
double alpha,
double k,
double c)
noexcept
96 if (!std::isfinite(ms) || !std::isfinite(a) || !std::isfinite(alpha)
97 || !std::isfinite(k) || !std::isfinite(c))
99 ms_ = std::max(ms, 1.0);
100 a_ = std::max(a, 1.0);
101 alpha_ = std::max(alpha, 0.0);
102 k_ = std::max(k, 1.0);
103 c_ = std::clamp(c, 0.0, 0.999);
118 const double chiAn = ms_ / (3.0 * a_);
119 return c_ * chiAn / (1.0 - c_ * alpha_ * chiAn);
133 if (!std::isfinite(fieldH))
return static_cast<T
>(m_);
135 const double h =
static_cast<double>(fieldH);
136 const double hDot = fs2_ * (h - hPrev_) - hDotPrev_;
139 double m = m_ + 2.0 * invFs2_ * wPrev_;
140 const double rhs = m_ + invFs2_ * wPrev_;
142 double w = 0.0, dwdm = 0.0;
143 for (
int it = 0; it < 4; ++it)
145 evaluate(m, h, hDot, w, dwdm);
146 const double g = m - rhs - invFs2_ * w;
147 const double gp = 1.0 - invFs2_ * dwdm;
148 const double dm = g / gp;
150 if (std::abs(dm) < 1e-9 * ms_)
154 m = std::clamp(m, -ms_, ms_);
156 evaluate(m, h, hDot, w, dwdm);
161 return static_cast<T
>(m);
166 static void langevin(
double x,
double& l,
double& lp,
double& lpp)
noexcept
168 const double ax = std::abs(x);
172 const double x2 = x * x;
173 l = x * (1.0 / 3.0 - x2 / 45.0);
174 lp = 1.0 / 3.0 - x2 / 15.0;
175 lpp = -2.0 * x / 15.0;
180 l = (x > 0.0 ? 1.0 : -1.0) - 1.0 / x;
182 lpp = -2.0 / (x * x * x);
186 const double e = std::exp(x);
187 const double ie = 1.0 / e;
188 const double sh = 0.5 * (e - ie);
189 const double ch = 0.5 * (e + ie);
190 const double coth = ch / sh;
191 const double csch2 = 1.0 / (sh * sh);
192 const double ix = 1.0 / x;
194 lp = ix * ix - csch2;
195 lpp = 2.0 * (csch2 * coth - ix * ix * ix);
200 void evaluate(
double m,
double h,
double hDot,
double& w,
double& dwdm)
const noexcept
209 const double q = (h + alpha_ * m) / a_;
210 double l = 0.0, lp = 0.0, lpp = 0.0;
211 langevin(q, l, lp, lpp);
213 const double mAn = ms_ * l;
214 const double dM = mAn - m;
215 const double delta = (hDot > 0.0) ? 1.0 : -1.0;
216 const double deltaM = (dM * delta > 0.0) ? 1.0 : 0.0;
219 const double oneMc = 1.0 - c_;
220 double d1 = oneMc * delta * k_ - alpha_ * dM;
221 const double d1Min = 0.01 * oneMc * k_;
222 if (std::abs(d1) < d1Min)
223 d1 = (d1 >= 0.0) ? d1Min : -d1Min;
225 const double phi1 = oneMc * deltaM * dM / d1;
226 const double cChiLp = c_ * chi_ * lp;
228 const double num = phi1 + cChiLp;
234 double den = 1.0 - alpha_ * cChiLp;
235 if (std::abs(den) < 0.01)
236 den = (den >= 0.0) ? 0.01 : -0.01;
237 w = hDot * num / den;
240 const double alphaOverA = alpha_ / a_;
241 const double dmAn = ms_ * lp * alphaOverA - 1.0;
242 const double dPhi1 = oneMc * deltaM * dmAn * (oneMc * delta * k_) / (d1 * d1);
243 const double dLp = lpp * alphaOverA;
244 const double dNum = dPhi1 + c_ * chi_ * dLp;
245 const double dDen = -alpha_ * c_ * chi_ * dLp;
246 dwdm = hDot * (dNum * den - num * dDen) / (den * den);
250 double ms_ = 3.5e5, a_ = 2.2e4, alpha_ = 1.6e-3, k_ = 2.7e4, c_ = 1.7e-1;
251 double chi_ = 3.5e5 / 2.2e4;
253 double invFs2_ = 0.5 / 48000.0;
254 double fs2_ = 2.0 * 48000.0;
258 double hDotPrev_ = 0.0;
void setParameters(double ms, double a, double alpha, double k, double c) noexcept
Sets the Jiles-Atherton parameters.