Take a look at testnet today. We're in the middle of a brutal test and it's looking very good!
http://testnet.geekhash.org/
This phase of the test started at around 1700 - you can see the drop in the red 'difficulty' line as the test was reset. The approx 2MH/s was my and Blaksmith's hashing. TheQueen74 paid us a visit from the City of Light and kicked things up a bit. The block times look good overall in spite of some ~30 minute blocks on the 'down hill' side of things.
The days of long CAT blocks and slow confirms are almost over.
Looking good on the testnet!
Is that still using the 12% lower limit? A good PID should obviate the need for the lower limit, it just makes for some very very long blocktimes after an attack. If it's been a couple hours since the last block, let the diff drop up to 25%.
Here is the end of the test, and it looks like it was a successful test.

For those interested, there is no "% limit". A true PID doesn't have limits, other than a max and min level that it is allowed to travel. As stated on the testnet page
Current solution used: PID with 8 block averaging with 20 second dead zone.
Dip of difficulty to 0 denotes catcoind change time.
Last 100 blocks in text.
Slow gains: pGain=-0.005125, iGain=-0.0225, dGain=-0.0075 - When average between 2.5 and 17.5 min.
Fast gains: pGain=-0.005125, iGain=-0.0525, dGain=-0.0075 - When average is outside 2.5 and 17.5 min.
And for those really curious at the code in the catcoind:
i=0; // Zero bit-shift counter
while(bnNew>0) // Loop while bnNew > 0
{
i++; // Increment bit-shift counter
bnNew = bnNew >> 1; // shift bnNew lower by 1 bit
if(i>256) bnNew = 0; // overflow test, just to make sure that it never stays in this loop
}
bnNew.SetCompact(pindexLast->nBits); // Get current difficulty again
error = nActualTimespan - nTargetSpacing; // Calculate the error to be fed into the PID Calculation
if(error >= -450 && error <= 450) // Slower gains for when the average time is within 2.5 min and 7.5 min
{
pCalc = pGainUp * (double)error; // Calculate P ... pGain defined at beginning of routine
iCalc = iGainUp * (double)error * (double)((double)nTargetSpacing / (double)nActualTimespan); // Calculate I ... iGain defined at beginning of routine
dCalc = dGainUp * ((double)error / (double)nActualTimespan) * iCalc; // Calculate D ... dGain defined at beginning of routine
}
else // Faster gains for block averages > 7.5 minutes or faster than 2.5 minutes
{
pCalc = pGainDn * (double)error; // Calculate P ... pGain defined at beginning of routine
iCalc = iGainDn * (double)error * (double)((double)nTargetSpacing / (double)nActualTimespan); // Calculate I ... iGain defined at beginning of routine
dCalc = dGainDn * ((double)error / (double)nActualTimespan) * iCalc; // Calculate D ... dGain defined at beginning of routine
}
if(error > -10 && error < 10) // 20 second dead zone, between 9:50 and 10:10 minute block average
{
if(fTestNet) printf("Within dead zone. No change! error: %"PRI64d"\n", error);
return(bnNew.GetCompact());
}
dResult = pCalc + iCalc + dCalc; // Sum the PID calculations
result = (int64)(dResult * 65536); // Adjust for scrypt calcuation
while(result > 8388607) result = result / 2; // Bring the result within max range for overflow condition
bResult = result; // Set the bignum value
if(i>24) bResult = bResult << (i - 24); // bit-shift integer value of result to be subtracted from current diff
Output for testnet spam log:
2014-03-06 20:44:35 pCalc: -1.107000, iCalc: -3.573529, dCalc: 0.007095, Result: -306278 (-4.673435)
2014-03-06 20:44:35 Actual Time: 816, error: 216
2014-03-06 20:44:35 Result: 1ccac660 000000004ac66000000000000000000000000000000000000000000000000000
2014-03-06 20:44:35 Before: 1d0c4a91 0000000c4a910000000000000000000000000000000000000000000000000000
2014-03-06 20:44:35 After: 1d0c9557 0000000c95576000000000000000000000000000000000000000000000000000
After dResult is calculated, it is converted into an integer to be applied to the current difficulty.