%% $RCSfile: sdspvfdly2.tlc,v $ %% $Revision: 1.10 $ %% $Date: 2000/08/29 22:27:00 $ %% %% Dale Shpak, R. Firtion %% Copyright (c) 1995-2000 The MathWorks, Inc. %% %% Abstract: Variable Fractional Delay %% %implements sdspvfdly2 "C" %include "dsplib.tlc" %include "dsp_ic.tlc" %% Function: BlockTypeSetup ================================================ %% Abstract: %% %function BlockTypeSetup(block, system) void %% Render the clipDelayValue function %% First, cache the function prototype for clipDelayValue: %% %openfile clipDelayBuff extern int clipDelayValue(real_T *delay, int_T dmax); %closefile clipDelayBuff % %% Next, cache the clipDelayValue function itself: %% %openfile clipDelayBuff /* Function: clipDelayValue * Rounds the delay values if they are greater than the maximum * or are not whole numbers. */ extern int clipDelayValue( real_T *delay, int_T dmax) { /* Clip delay time to legal range: [0,dmax] */ real_T dly = *delay; if (dly < 0.0) { dly = 0.0; } else if (dly > (real_T)dmax) { dly = (real_T)dmax; } *delay = dly; return((int_T)dly); /* Integer part of delay time */ } /* clipDelayValue */ %closefile clipDelayBuff % %endfunction %% BlockTypeSetup %% Function: BlockInstanceSetup =============================================== %% %% Abstract: %% Name the S-function parameters %function BlockInstanceSetup (block, system) void %% %assign INPORT = 0 %assign DELAY_PORT = 1 %assign OUTPORT = 0 %assign FILT = SFcnParamSettings.FILTER %assign portWidth = LibDataInputPortWidth(INPORT) %assign cplx_in = LibBlockInputSignalIsComplex(INPORT) %assign sl_dtype_in = LibBlockInputSignalDataTypeName(INPORT,"%") %assign dtype_in = (cplx_in) ? "c" + sl_dtype_in : sl_dtype_in %% %assign dmax = SFcnParamSettings.maxDelay %assign isFrame = LibBlockInputSignalIsFrameData(INPORT) %assign nChans = SFcnParamSettings.ICs_nChans %assign nSamps = portWidth / nChans %assign buffLen = LibBlockDWorkWidth(BUFF)/nChans %assign filterLen = SIZE(FILT,1) %% %assign incrementDelayPerChannel = SFcnParamSettings.incrementDelayPerChannel %assign incrementDelayPerSample = SFcnParamSettings.incrementDelayPerSample %% %assign numPhases = SFcnParamSettings.NUM_PHASES %if (filterLen == 1 && FILT[0] == 0.0) %assign hLen = 0 %else %assign hLen = filterLen / (2 * numPhases) %endif %assign block = block + INPORT + OUTPORT + DELAY_PORT \ + FILT + hLen + portWidth + dtype_in + cplx_in + dmax \ + buffLen + filterLen + isFrame + nChans + nSamps + numPhases \ + incrementDelayPerChannel + incrementDelayPerSample %% Setup the initial condition handler: %% % %endfunction %% BlockInstanceSetup %% Function: InitializeConditions ============================================= %% %% Abstract: %% Initialize the DWork vector (Buffer) to the initial values specified. %% %function InitializeConditions(block, system) Output /* DSP Blockset Variable Fractional Delay (%) - % */ %% % = %; %% % %endfunction %% Function: Outputs ========================================================== %% %function Outputs(block, system) Output { /* DSP Blockset Variable Fractional Delay (%) - % */ %% %% Block could be multirate if and only if it has more than %% one input port (eg, a "Delay" input). If it is multirate, %% generate "sample hit" conditional so code executes at the %% block's base rate, and not the overall model base rate. %% %assign differentPortRates = !LibIsSFcnSingleRate(block) %% %if differentPortRates if (%) { % %endif %% %assign delayLen = LibDataInputPortWidth(DELAY_PORT) %% % *u = %; % *buff = %; % *y = %; % *in_curr; real_T t = 0.0; int_T ti = 0; int_T i,j; real_T *dptr = %; for (i=0; i++ < %; ) { int_T buffstart = %; /* For a scalar delay input, we need to reset t and ti for each channel: */ t = *dptr; ti = clipDelayValue(&t, %); for (j=0; j++ < %; ) { if (++buffstart == %) buffstart = 0; /* Rotate circular buffer */ *(buff + buffstart) = *u++; %if (incrementDelayPerSample) t = *dptr++; /* Get delay time from 2nd input port */ ti = clipDelayValue(&t, %); %else t = *dptr; ti = clipDelayValue(&t, %); %endif /* Output new interpolation point */ in_curr = buff; %if (hLen > 0) /* Check if we need to use linear interp: */ if (ti < %) { %else { %endif /* Linear interpolation: */ real_T frac = t - ti; /* Fractional part of delay time */ real_T frac1 = 1 - frac; /* Add offset to current input pos'n in buffer, backing up by * the integer number of delay samples. If we've backed up too * far past the start of the buffer, wrap to the end: */ ti = buffstart - ti; if (ti < 0) ti += %; in_curr += ti; /* Get pointer into buffer */ if (ti > 0) { /* The two points are adjacent in memory: */ %if (cplx_in) y->re = in_curr[0].re * frac1 + in_curr[-1].re * frac; (y++)->im = in_curr[0].im * frac1 + in_curr[-1].im * frac; %else *y++ = in_curr[0] * frac1 + in_curr[-1] * frac; %endif } else { /* The two points are at the end and start of buffer: */ %if (cplx_in) y->re = in_curr[0].re * frac1 + in_curr[%].re * frac; (y++)->im = in_curr[0].im * frac1 + in_curr[%].im * frac; %else *y++ = in_curr[0] * frac1 + in_curr[%] * frac; %endif } %if (hLen == 0) } %else } else { /* FIR Interpolation: */ %assign firFilterLen = filterLen / numPhases %assign coeffs = "" %assign count = 0 const real_T filter[%] = { %foreach Idx = numPhases %foreach Idx2 = firFilterLen %assign coeffs = coeffs + "%" %assign count = count + 1 %if (count < filterLen) %assign coeffs = coeffs + ", " %else %assign coeffs = coeffs + " };" %endif %endforeach % %assign coeffs = "" %endforeach const real_T frac = t - ti; /* Fractional part of delay time */ int_T phase = (int_T) (% * frac + 0.5); /* [0,nphases] */ if (phase == %) { ++ti; phase = 0; } /* Add offset to current input pos'n in buffer, backing up by the * integer number of delay samples then incrementing by half the * filter length. If we've backed up too far past the start of the * buffer, wrap: */ ti = buffstart - ti + %; if (ti < 0) ti += %; in_curr += ti; /* Get pointer into buffer */ if (ti+1 >= %) { /* Contiguous input samples in buffer: */ /* Point to correct polyphase filter */ const real_T *filt = filter + phase*%; int_T kn; %if (cplx_in) y->re = y->im = 0.0; for(kn=0; kn< %; kn++) { y->re += in_curr[-kn].re * *filt; y->im += in_curr[-kn].im * *filt++; } %else *y = 0.0; for(kn=0; kn <%; kn++) { *y += in_curr[-kn] * *filt++; } %endif ++y; } else { /* Discontiguous input samples in buffer: */ const real_T *filt = filter + phase*%; const int_T k1 = ti + 1; const int_T k2 = % - k1; const % *in_last = in_curr - ti + %; int_T kn; %if (cplx_in) y->re = y->im = 0.0; for(kn=0; kn re += in_curr[-kn].re * *filt; y->im += in_curr[-kn].im * *filt++; } for(kn=0; kn < k2; kn++) { y->re += in_last[-kn].re * *filt; y->im += in_last[-kn].im * *filt++; } %else *y = 0.0; for(kn=0; kn ; %if (incrementDelayPerSample && delayLen == nSamps) dptr -= %; %endif %if (incrementDelayPerChannel) dptr++; %endif } %% % += %; while (% >= %) % -= %; %if differentPortRates } %endif } %endfunction %% Outputs %% [EOF] sdspvfdly2.tlc