%% $RCSfile: sdspsdyad2.tlc,v $ %% $Revision: 1.2 $ %% $Date: 2000/06/15 20:37:49 $ %% %% Copyright 1995-2000 The MathWorks, Inc. %% %% Abstract: Dyadic synthesis filter bank %% %implements sdspsdyad2 "C" %include "dsplib.tlc" %% Function: BlockInstanceSetup =============================================== %% %function BlockInstanceSetup(block, system) void %% We do not support discontiguous inputs %foreach i = NumDataInputPorts %if (!IsInputPortContiguous(block,i)) % %endif %endforeach %assign ASYMMETRIC = 1 %assign SYMMETRIC = 2 %assign TREE = SFcnParamSettings.TREE %% Port info %assign OUTPORT = 0 %assign OUTPORTWIDTH = LibDataOutputPortWidth(OUTPORT) %assign numDims = LibBlockOutputSignalNumDimensions(OUTPORT) %assign dims = LibBlockOutputSignalDimensions(OUTPORT) %assign outCols = (numDims == 2) ? dims[1] : 1 %assign outRows = dims[0] %assign FRAMEBASED = LibBlockOutputSignalIsFrameData(OUTPORT) %assign SAMPLE_BASED = !FRAMEBASED %assign NUM_CHANS = FRAMEBASED ? outCols : OUTPORTWIDTH %assign FRAME = FRAMEBASED ? outRows : 1 %assign FILT_LEVEL = 1 %% default %assign LFILT = SFcnParamSettings.LFILT %assign HFILT = SFcnParamSettings.HFILT %assign LP_ORDER = CAST("Number", SIZE(SFcnParamSettings.LFILT,0) * SIZE(SFcnParamSettings.LFILT,1) - 1) %assign HP_ORDER = CAST("Number", SIZE(SFcnParamSettings.HFILT,0) * SIZE(SFcnParamSettings.HFILT,1) - 1) %assign FILT_COMPLEX = TYPE(SFcnParamSettings.LFILT[0]) == "Complex" %assign IN_COMPLEX = LibBlockInputSignalIsComplex(0) %assign OUT_COMPLEX = (IN_COMPLEX || FILT_COMPLEX) %assign NUM_LEVELS = SFcnParamSettings.LEVELS %assign OUTBUFF_SIZE = LibBlockDWorkWidth(OutBuff) / 2 %assign LPBUFFSIZE = LibBlockDWorkWidth(FiltBuff) / 2 %if (TREE == ASYMMETRIC) %assign NUM_FILTERS = 2 * NUM_LEVELS %else %assign FILT_LEVEL = 2 %assign NUM_FILTERS = 2 %foreach II = NUM_LEVELS-1 %assign FILT_LEVEL = FILT_LEVEL * 2 %assign NUM_FILTERS = NUM_FILTERS + FILT_LEVEL %endforeach %endif %assign DAT_T = (IN_COMPLEX) ? "creal_T" : "real_T" %assign FILT_T = (FILT_COMPLEX) ? "creal_T" : "real_T" %assign OUT_T = (OUT_COMPLEX) ? "creal_T" : "real_T" %assign block = block + OUTPORT + OUTPORTWIDTH + LFILT + HFILT + \ LP_ORDER + HP_ORDER + FILT_COMPLEX + IN_COMPLEX + OUT_COMPLEX + \ NUM_LEVELS + NUM_CHANS + TREE + ASYMMETRIC + SYMMETRIC + \ OUTBUFF_SIZE + LPBUFFSIZE + SAMPLE_BASED + FRAME + \ NUM_FILTERS + FILT_LEVEL + DAT_T + FILT_T + OUT_T %endfunction %% BlockInstanceSetup %% Function: InitializeConditions ============================================= %% %% Abstract: %% Initialize the DWork vector (Buffer) to the initial values specified. %% %function InitializeConditions(block, system) Output %% { /* % Block: % (%) */ %assign LP_LENGTH = CAST("Number", SIZE(SFcnParamSettings.LFILT,0) * SIZE(SFcnParamSettings.LFILT,1)) %assign HP_LENGTH = CAST("Number", SIZE(SFcnParamSettings.HFILT,0) * SIZE(SFcnParamSettings.HFILT,1)) /* Filter coefficients */ %assign astr = "" %assign count = 0 %if (FILT_COMPLEX) static creal_T lfilt[%] = { %foreach Idx = LP_LENGTH %assign astr = astr + "{%,%}" %assign count = count + 1 %if (count < LP_LENGTH) %assign astr = astr + "," %else %assign astr = astr + "};" %endif %if (count % 2 == 0 || count == LP_LENGTH) % %assign astr = "" %endif %endforeach %assign count = 0 static creal_T hfilt[%] = { %foreach Idx = HP_LENGTH %assign astr = astr + "{%,%}" %assign count = count + 1 %if (count < HP_LENGTH) %assign astr = astr + "," %else %assign astr = astr + "};" %endif %if (count % 2 == 0 || count == HP_LENGTH) % %assign astr = "" %endif %endforeach %else static real_T lfilt[%] = { %foreach Idx = LP_LENGTH %assign astr = astr + "%" %assign count = count + 1 %if (count < LP_LENGTH) %assign astr = astr + "," %else %assign astr = astr + "};" %endif %if (count % 4 == 0 || count == LP_LENGTH) % %assign astr = "" %endif %endforeach %assign count = 0 static real_T hfilt[%] = { %foreach Idx = HP_LENGTH %assign astr = astr + "%" %assign count = count + 1 %if (count < HP_LENGTH) %assign astr = astr + "," %else %assign astr = astr + "};" %endif %if (count % 4 == 0 || count == HP_LENGTH) % %assign astr = "" %endif %endforeach %endif { /* Initialize pointers to filter coefficients . */ %assign NUM_FILTERS2 = NUM_FILTERS / 2 %% Initialized in pairs int_T k=0; /* We also retain pointers to the beginning of each filter */ %roll sigIdx1 = [ 0:% ], lcv1 = 2, block, "InlineRoller" % = lfilt; % = hfilt; %endroll %% FILTERS } % = 1; /* Output ready flag */ %if (TREE == ASYMMETRIC && SAMPLE_BASED) %% % = 0; /* Initialize input sample counter */ %assign rollVars = [ "/I2Idx" ] %roll sigIdx1 = [ 0:% ], lcv1 = 2, block, "Roller", rollVars % = 0; %endroll %% Levels %endif %assign rollVars = [ "/MemIdx" ] %roll sigIdx1 = [ 0:% ], lcv1 = 2, block, "Roller", rollVars % = 0; %endroll %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Compute Latency properties and set counters appropriately %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %assign isSingleRate = LibIsSFcnSingleRate(block) %assign isMultiTasking = IsModelMultiTasking() %assign OutBuffSize = LibBlockDWorkWidth(OutBuff) %% /* Set output buffer index based on block rate and model tasking mode */ %if(isSingleRate || !isMultiTasking) %% %if(TREE == SYMMETRIC) %assign num = (SAMPLE_BASED) ? OUTPORTWIDTH : 1 % = %; %else % = 2; %if(!isSingleRate) % %endif %endif %else /* MultiRate and MultiTasking */ % % = 0; %endif } %endfunction %% Function: InitOutBuffer ========================================================== %% %function InitOutBuffer(OutBuffSize, OUT_COMPLEX) Output /* Initialize Output Buffer */ { int_T i; for(i=0; i<%; i++) { %if OUT_COMPLEX %0")> = 0.0; %0")> = 0.0; %else % = 0.0; %endif } } %endfunction %% InitOutBuffer %% Function: Outputs ========================================================== %% %function Outputs(block, system) Output %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% PROCESS INPUTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% { /* % Block: % (%) */ /* UPDATE INPUTS */ % *cffLBase = (% *) %; % *cffHBase = (% *) %; %assign astr = "" %foreach II = NumDataInputPorts-1 %assign astr = astr + "%, " %endforeach /* Input port addresses. Lowest-rate port first */ % *inPorts[%] = { % % }; %if (SAMPLE_BASED && TREE == ASYMMETRIC) %% %assign WHOLE_FRAME = 1 %foreach II = NUM_LEVELS %assign WHOLE_FRAME = WHOLE_FRAME * 2 %endforeach %% %assign IN_FRAME = WHOLE_FRAME %% % %% /* Check if we have enough samples to process */ if (% == %) { % = 0; /* Reset input sample counter */ inputReady = 1; } if (inputReady) { %% %else %if !LibIsSFcnSingleRate(block) %assign input_port = "InputPortIdx%" if (%) { %endif %endif %% % *mem0 = %; % *sumBuff0 = %; % *out = %; % *inBuff0 = %; if (%) out += %; { %if (NUM_CHANS > 1) /* Process each channel */ %endif %% %% Roll over the channels %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %%assign rollVars = ["/InBuff"] %roll sigIdx1 = [ 0:% ], lcv1 = 2, block, "InlineRoller" % *sumBuff = sumBuff0; int_T pwIdx = 0; int_T filtIdx = 0; int_T numSamps = %; % *inBuff = inBuff0; %if (!SAMPLE_BASED) /* Read in the input frames from all input ports */ % *inPtr = inBuff0; int_T aframe = numSamps; %roll sigIdx2 = [ 0:% ], lcv2 = 2, block, "InlineRoller" % *uptr = inPorts[%] + %*aframe; int_T i; for (i=0; i++ < aframe; ) { %if (!IN_COMPLEX && FILT_COMPLEX) inPtr->re = *uptr++; (inPtr++)->im = (real_T) 0.0; %else *inPtr++ = *uptr++; %endif } %if (TREE == ASYMMETRIC) if (% > 0) aframe = aframe*2; %endif %endroll %% %else %% %if (TREE == SYMMETRIC) /* Read in the input samples from all input ports */ % *inPtr = inBuff0; %roll sigIdx2 = [ 0:% ], lcv2 = 2, block, "InlineRoller" % *uptr = inPorts[%] + %; %if (!IN_COMPLEX && FILT_COMPLEX) inPtr->re = *uptr++; (inPtr++)->im = (real_T) 0.0; %else *inPtr++ = *uptr++; %endif %endroll %else inBuff = inBuff0 + % * %; %endif %endif %% if(!SAMPLE_BASED) %%%%%%%%%%%%%%%%%%%%%%%%%%% { %if (TREE == SYMMETRIC) % %else % %endif } %endroll %% %% End of roll over the Channels %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %if !LibIsSFcnSingleRate(block) } %endif % = (boolean_T)!(%); } /* if(inputReady) */ } /* end update inputs */ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% PROCESS OUTPUTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% { /* % Block: % (%) */ /* PROCESS OUTPUTS */ %if !LibIsSFcnSingleRate(block) if (%) { %endif %if (SAMPLE_BASED) /* Outputs grouped by channel */ %assign OUT_FRAME = OUTBUFF_SIZE / OUTPORTWIDTH % *y = % + %; % *yout = %; if (% >= %) y += (%); %roll sigIdx1 = [ 0:% ], lcv1 = 1, block, "InlineRoller" *yout++ = *y; y += %; %endroll if (++(%) >= %) % = 0; %else % *y = %; % *yout = %; if (% > 0) y += %; %roll sigIdx1 = [ 0:% ], lcv1 = 1, block, "InlineRoller" *yout++ = *y++; %endroll if (% > 0) % = 0; else % = 1; %endif %if !LibIsSFcnSingleRate(block) } /* Sample hit */ %endif } %endfunction %% Output %% Function: SAMPLEBASED_ASYMMETRIC ======================================== %% %function SampleBased_ASymmetric(block,InputPortTIDs,NumDataInputPorts,WHOLE_FRAME) Output %% /* We delay processing until we buffer the minimum number of samples * that are required to generate an entire output frame. * For asymmetric trees, this time is when we have a hit from * input port zero (the lowest-rate port). * * The data is grouped by channel, LOWEST!! rate data first. */ int_T offset = 0; int_T minFrame = 1; boolean_T inputReady = 0; %% %if !LibIsSFcnSingleRate(block) %assign initStr = "" %assign NumInputTids = SIZE(InputPortTIDs,1) %foreach idx = NumInputTids %% Get global TID for each Input port: %assign initStr = initStr + "%" + ... "%<(idx+1) == SIZE(InputPortTIDs,1) ? "": ", ">" + ... "%<(idx+1) % 20 == 0? STRING("\n"): "">" %endforeach /* The tids are in reverse order -> lowest rate first */ static const int_T tids[%] = {%}; %endif %assign rollVars = [ "/I2Idx" ] %roll sigIdx1 = [ 0:% ], lcv1 = 1, block, "Roller", rollVars %if !LibIsSFcnSingleRate(block) %assign tidstr = "tids[%]" %% tidstr is the GLOBAL TID, so use LibIsSampleHit, not LibIsSFcnSampleHit: if (%) { %endif % *uptr = inPorts[%]; % *inBuff = % + offset + %; %roll sigIdx2 = [ 0:% ], lcv2 = 2, block, "InlineRoller" %if (!IN_COMPLEX && FILT_COMPLEX) inBuff->re = *uptr++; inBuff->im = (real_T) 0.0; %else *inBuff = *uptr++; %endif inBuff += %; %endroll if (++(%) == minFrame) % = 0; (%)++; /* Input sample counter */ %if !LibIsSFcnSingleRate(block) } %endif offset += minFrame; if (% > 0) minFrame *= 2; %endroll %% INPUT_PORTS %% %endfunction %% SAMPLEBASED_ASYMMETRIC %% Function: SYMMETRIC ============================================= %% %function Symmetric(block,lcv1,sigIdx1) Output %% int_T numFiltPairs = %; %if (NUM_LEVELS > 1) /* Loop through the levels */ %endif %roll sigIdx2 = [ 0:% ], lcv2 = 2, block, "InlineRoller" int_T numSamps2 = 2 * numSamps; int_T ii; inBuff = %; sumBuff = sumBuff0; /* Process the filter pairs at this level */ for (ii=0; ii < numFiltPairs; ii++) { int_T mIdx = %; % *cffPtr = %; % *in = inBuff; % *optr = sumBuff; int_T thePhase = 0; int_T i; /* Each channel uses the same filter phase but * accesses its own state memory and input. */ /* Lowpass filter */ % if (% == %) % = mIdx; % = cffPtr; mem0 += %; /* Highpass Filter */ mIdx = %; cffPtr = %; thePhase = 0; in = inBuff + numSamps; optr = sumBuff + numSamps2; % if (% == %) % = mIdx; % = cffPtr; mem0 += %; ++pwIdx; %if (NUM_LEVELS > 1) if (% == %) { %else { %endif int_T m; /* Write to the output buffer */ for (m=0; m < numSamps2; m++) { %if (OUT_COMPLEX) out->re = sumBuff[m].re + sumBuff[m+numSamps2].re; (out++)->im = sumBuff[m].im + sumBuff[m+numSamps2].im; %else *out++ = sumBuff[m] + sumBuff[m+numSamps2]; %endif } %if (NUM_LEVELS > 1) } else { /* Next input frame is the sum of the two filter outputs. * We can overwrite the input data since we are done with it * and it has exactly the same number of samples as the input. */ int_T m; for (m=0; m < numSamps2; m++) { %if (OUT_COMPLEX) inBuff[m].re = sumBuff[m].re + sumBuff[m+numSamps2].re; inBuff[m].im = sumBuff[m].im + sumBuff[m+numSamps2].im; %else inBuff[m] = sumBuff[m] + sumBuff[m+numSamps2]; %endif } inBuff += numSamps2; %endif } } numSamps = numSamps2; numFiltPairs /= 2; %endroll %% LEVELS %% %endfunction %% SYMMETRIC %% Function: ASYMMETRIC ============================================= %% %function Asymmetric(block,lcv1,sigIdx1) Output %% /* Initialize the sum buffer with the low-rate lowpass input data */ int_T i; for (i=0; i < numSamps; i++) sumBuff[i] = inBuff[i]; inBuff += numSamps; { %if (NUM_LEVELS > 1) /* Loop through the levels */ %endif %roll sigIdx2 = [ 0:% ], lcv2 = 2, block, "InlineRoller" int_T mIdx = %; % *cffPtr = %; % *in = sumBuff; % *optr = sumBuff + 2 * numSamps; int_T thePhase = 0; /* Lowpass filter */ % if (% == %) % = mIdx; % = cffPtr; mem0 += %; /* Highpass Filter accesses the same inputs and has the same phase */ mIdx = %; cffPtr = %; thePhase = 0; in = inBuff; optr = sumBuff; % if (% == %) % = mIdx; % = cffPtr; mem0 += %; inBuff += numSamps; ++pwIdx; numSamps *= 2; %if (NUM_LEVELS > 1) if (% == %) { %else { %endif /* Write to the output buffer */ int_T j; for (j=0; j < numSamps; j++) { %if (OUT_COMPLEX) out->re = sumBuff[j].re + sumBuff[j+numSamps].re; (out++)->im = sumBuff[j].im + sumBuff[j+numSamps].im; %else *out++ = sumBuff[j] + sumBuff[j+numSamps]; %endif } %if (NUM_LEVELS > 1) } else { /* Next LP input frame is the sum of the two filter outputs */ int_T j; for (j=0; j < numSamps; j++) { %if (OUT_COMPLEX) sumBuff[j].re += sumBuff[j+numSamps].re; sumBuff[j].im += sumBuff[j+numSamps].im; %else sumBuff[j] += sumBuff[j+numSamps]; %endif } %endif } %endroll %% LEVELS } %endfunction %% Asymmetric %% Function: FILTER ============================================= %% %function Filter(block,pass) Output %% %% If this is a high pass filter then set the LP_ORDER equal %% to the HP_ORDER. Otherwise use LP_ORDER as is. %% %assign FILTER_ORDER = (pass == "High") ? HP_ORDER : LP_ORDER %% for (i=0; i < numSamps; i++) { % u = *in++; int_T m; /* Generate the output samples */ for (m=0; m < 2; m++) { %if (FILTER_ORDER > 2) % *mem = mem0 + mIdx; /* Most recently saved input */ int_T j = 0; %endif % sum; %if (FILT_COMPLEX) %% %% Complex Filt and Complex Input %% sum.re = CMULT_RE(u, *cffPtr); sum.im = CMULT_IM(u, *cffPtr); ++cffPtr; %% %% Protect against filter length of 2 %if (FILTER_ORDER > 2) for (j=0; j <= mIdx; j++) { sum.re += CMULT_RE(*mem, *cffPtr); sum.im += CMULT_IM(*mem, *cffPtr); --mem; ++cffPtr; } /* mem was pointing at the -1th element. Move to end. */ mem += %; while (j++ < %) { sum.re += CMULT_RE(*mem, *cffPtr); sum.im += CMULT_IM(*mem, *cffPtr); --mem; ++cffPtr; } %endif %elseif (IN_COMPLEX) %% %% Real Filt and Complex Input %% sum.re = u.re * *cffPtr; sum.im = u.im * *cffPtr++; %% %% Protect against filter length of 2 %if (FILTER_ORDER > 2) for (j=0; j <= mIdx; j++) { sum.re += mem->re * *cffPtr; sum.im += (mem--)->im * *cffPtr++; } /* mem was pointing at the -1th element. Move to end. */ mem += %; while (j++ < %) { sum.re += mem->re * *cffPtr; sum.im += (mem--)->im * *cffPtr++; } %endif %else %% %% Real Filt and Real Input %% sum = u * *cffPtr++; %% %% Protect against filter length of 2 %if (FILTER_ORDER > 2) for (j=0; j <= mIdx; j++) sum += *mem-- * *cffPtr++; /* mem was pointing at the -1th element. Move to end. */ mem += %; while (j++ < %) sum += *mem-- * *cffPtr++; %endif %endif *optr++ = sum; ++thePhase; } /* Update the counters modulo their buffer size */ if (thePhase == 2) thePhase = 0; if (thePhase == 0) { if (++mIdx >= %) mIdx = 0; /* Save the current input value */ mem0[mIdx] = u; %% %assign cffBase = (pass=="High") ? "cffHBase" : "cffLBase" cffPtr = %; } } /* Frame */ %% %endfunction %% Filter %% [EOF] sdspsdyad.tlc