Looks more like +61 dB to me (I don't know Matlab though). I think the problem is related to the size of numbers. You show 18 bit length, 2^18 ~ 8x10^5 which is ~ 60 dB. Convert the input numbers to fractional sizes by dividing each number by 2^18 before feeding it to the floating point routines. I'm just guessing here - every time I try to use Matlab I give up and write my own program!
Dr. Mike - The CIC filter only works with fixed point math. Everything that I've read indicates that the algorithm isn't compatible with floating point. I suspect that it is because the filter consists only of adds and subtracts - no multiplies. This puts floating point at a severe disadvantage because it has to denormalize the operands before any add or subtract. That means that the lsbs are dropped if the normalized exponents are ever different for the two operands. Since the input sample will usually have a different magnitude than the accumulation, bits will always be dropped exactly where the bits are needed to be retained. The usual problem of can't add a very small number to a very large number without a serious loss of resolution. This is always an interesting floating point issue... There used to be special number formats in some floating point implementations prior to IEEE standardization that allocated smaller exponents with larger mantissas to try to avoid this problem, but I haven't seen it available (other than perhaps in specialized scientific applications that don't use the IEEE format) in several decades.
Since dsplearn is using fixed point, I suspect that the problem is more along the lines that you first mentioned - the inputs are simply in the wrong scaling.
That's really good for estimating what a fixed point processor will do. I just assumed all Matlab routines were float - so being able to see the round off errors you mentioned is helpful. Fixed point != integer, so scaling does seem like the right place for dsplearn to start.
dsplearn: fixed point is also called "fractional". All numbers are between -1 and +1, they only hold a mantissa. You can also have the fixed point be any where so numbers are between -2^j and +2^j where j is the number of bits in front of the binary point. As Donald points out, you lose precision when you do this. I would start with j = 0 and then see how your routines work. If you need more head room you can increase j until things work.
Yeah, I play with CIC filters from time to time and Matlab requires that you purchase their fixed point add-in specifically for this filter. The textbooks that I have read also mention that it is a strictly fixed-point filter. It is used extensively to implement sigma-delta A/D converters. That is part of how the sigma-delta algorithm extends the precision from 1 bit to 24 bits. You can also use this filter to extend the resolution (definitely not the precision) of say, a 12-bit resolution converter to an 18 bit resolution converter by oversampling by a factor of 64 and then decimating. Of course, the precision is still 12 bits without the remainder of the sigma-delta process, but this is still useful in noisy environments. The many zeros of the CIC and the flexibility of configuring it to achieve the attenuation of high frequencies is useful in high noise environments (providing of course, that Nyquist wasn't violated).
your estimate of 4.35 dB is correct(time domain equation). Your model estimate is wrong(frequency domain).
Any idea how to update the model for the correct behavior?
Use time domain. inject input (x) as all ones (or 2^17) = dc.
pass through model and get output y then :
y will acquire dc value and settle, make sure y(end) is behaving
I modelled both FIR interpolator and CIC Interpolator for gain analysis in time domain and frequency domain.
Time domain: inject step input. compare output to input.
Frequency domain: impulse input followed by fft
For FIR: gain in time domain or frequency domain agree and are as expected
For CIC: gain in time domain follows CIC equation but frequency domain gives +20*log10(Rate change) extra.
For CIC interpolator in the freq domain, It looks like the gain in matlab is (R*M)^N, not (R*M)^N / R (per theory).
Even after cascading the filter with inverse of gain to get unity gain as given below, this gives additional gain of 20*log10(R)
m_gain = dfilt.scalar(1/gain(m_cic));
But when the gain offset is updated to (R*M)^N, it gets the unity gain.
m_gain = dfilt.scalar(1/((R*M)^N));
Finally I found the reason...
fft normally scales its output by sqrt(Resolution). As such normal fir as an example comes correct for gain.
However with cic the fft length increased by R and thus it creates fake scaling. The fft output must be divided by R to behave.
In other words it is artefact of this arbitrary scaling.
yes that is what I found but is wrong because time domain direct measurement agrees with formula. I think it is some artefact of fft that is not clear. It is not matlab issue but fft issue as I used standard fft.