[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[sc-users] Sources of NaN in a UGen?
Hi -
Writing a UGen to represent the "Chua's Circuit" chaotic oscillator, I
find that the UGen tends very quickly to outputting NaN, although I
can't tell why. The meat of the UGen only does multiplication and
addition (there are a couple of trivial divisions). Can anyone suggest
why this might be happening?
The UGen code is:
void ChuaL_next(ChuaL *unit, int inNumSamples)
{
float *out = ZOUT(0);
float freq = ZIN0(0);
double a = ZIN0(1);
double b = ZIN0(2);
double c = ZIN0(3);
double d = ZIN0(4);
double rr = ZIN0(5); // Reciprocal of r - to save on a
division operation
double h = ZIN0(6);
double x0 = ZIN0(7);
double y0 = ZIN0(8);
double z0 = ZIN0(9);
double xn = unit->xn;
double yn = unit->yn;
double zn = unit->zn;
float counter = unit->counter;
double xnm1 = unit->xnm1;
double ynm1 = unit->ynm1;
double znm1 = unit->znm1;
double frac = unit->frac;
float samplesPerCycle;
double slope;
if(freq < unit->mRate->mSampleRate){
samplesPerCycle = unit->mRate->mSampleRate /
sc_max(freq, 0.001f);
slope = 1.f / samplesPerCycle;
}
else {
samplesPerCycle = 1.f;
slope = 1.f;
}
if((unit->x0 != x0) || (unit->y0 != y0) || (unit->z0 != z0)){
xnm1 = xn;
ynm1 = yn;
znm1 = zn;
unit->x0 = xn = x0;
unit->y0 = yn = y0;
unit->z0 = zn = z0;
}
double dx = xn - xnm1;
for (int i=0; i<inNumSamples; ++i) {
if(counter >= samplesPerCycle){
counter -= samplesPerCycle;
frac = 0.f;
xnm1 = xn;
ynm1 = yn;
znm1 = zn;
double k1x, k2x, k3x, k4x,
k1y, k2y, k3y, k4y,
k1z, k2z, k3z, k4z,
kxHalf, kyHalf, kzHalf,
ymx, ymx3, ymx3b, hOverR, xnm1plus;
hOverR = h * rr;
// 4th order Runge-Kutta approximate solution
for differential equations
ymx = ynm1 - xnm1;
ymx3 = ymx * ymx * ymx;
ymx3b = ymx3 * b;
k1x = hOverR * (d * ymx - c * xnm1 - (a * xnm1
* xnm1 * xnm1) - ymx3b);
k1y = - (h * (d * ymx - znm1 - ymx3b));
k1z = h * ynm1;
kxHalf = k1x * 0.5;
kyHalf = k1y * 0.5;
kzHalf = k1z * 0.5;
ymx = ynm1 + kyHalf - xnm1 - kxHalf;
ymx3 = ymx * ymx * ymx;
ymx3b = ymx3 * b;
xnm1plus = xnm1 + kxHalf;
k2x = hOverR * (d * ymx - c * (xnm1 + kxHalf)
- (a * xnm1plus *
xnm1plus * xnm1plus) - ymx3b);
k2y = - (h * (d * ymx - znm1 - kzHalf - ymx3b));
k2z = h * (ynm1 + kyHalf);
kxHalf = k2x * 0.5;
kyHalf = k2y * 0.5;
kzHalf = k2z * 0.5;
ymx = ynm1 + kyHalf - xnm1 - kxHalf;
ymx3 = ymx * ymx * ymx;
ymx3b = ymx3 * b;
xnm1plus = xnm1 + kxHalf;
k3x = hOverR * (d * ymx - c * (xnm1 + kxHalf)
- (a * xnm1plus *
xnm1plus * xnm1plus) - ymx3b);
k3y = - (h * (d * ymx - znm1 - kzHalf - ymx3b));
k3z = h * (ynm1 + kyHalf);
xnm1plus = xnm1 + k3x;
k4x = hOverR * (d * ymx - c * (xnm1 + k3x) -
(a * xnm1plus *
xnm1plus * xnm1plus) - ymx3b);
k4y = - (h * (d * ymx - znm1 - k3z - ymx3b));
k4z = h * (ynm1 + k3y);
xn = xn + (k1x + 2.0*(k2x + k3x) + k4x) * ONESIXTH;
yn = yn + (k1y + 2.0*(k2y + k3y) + k4y) * ONESIXTH;
zn = zn + (k1z + 2.0*(k2z + k3z) + k4z) * ONESIXTH;
dx = xn - xnm1;
}
counter++;
ZXP(out) = (xnm1 + dx * frac) * 0.5f;
frac += slope;
}
unit->xn = xn;
unit->yn = yn;
unit->zn = zn;
unit->counter = counter;
unit->xnm1 = xnm1;
unit->ynm1 = ynm1;
unit->znm1 = znm1;
unit->frac = frac;
}
void ChuaL_Ctor(ChuaL* unit){
SETCALC(ChuaL_next);
unit->x0 = unit->xn = unit->xnm1 = ZIN0(7);
unit->y0 = unit->yn = unit->ynm1 = ZIN0(8);
unit->z0 = unit->zn = unit->znm1 = ZIN0(9);
unit->counter = 0.f;
unit->frac = 0.f;
ChuaL_next(unit, 1);
}
and the SC class:
ChuaL : ChaosGen {
*ar { arg freq=22050, a=0.3286, b=0.9336, c= -0.8126, d=0.399,
rr=0.6.reciprocal, h=0.05, xi=0.1, yi=0, zi=0, mul=1.0, add=0.0;
^this.multiNew('audio', freq, a, b, c, d, rr, h, xi,
yi, zi).madd(mul, add)
}
}
Thanks in advance for any advice -
Dan
P.S. Not sure if this is an "sc-users" or "sc-dev" issue so sorry for
sending to both lists, for those who read both.
--
http://www.mcld.co.uk