%% 参数设置 clear all; close all; clc; Fs = 5e9; % 采样率 5 GHz fc = 1e9; % 载波频率 1 GHz bw = 5e6; % 信号带宽 5 MHz duration = 20e-6; % 信号持续时间 20 μs t = 0:1/Fs:duration-1/Fs; %% 生成QPSK调制信号 fprintf('生成QPSK调制信号...\n'); symbol_rate = bw/2; % 符号率 2.5 MHz sps = floor(Fs/symbol_rate); % 每符号采样点数 num_symbols = ceil(length(t)/sps); data = randi([0 3], 1, num_symbols); % QPSK数据 modulated = pskmod(data, 4, pi/4); % QPSK调制 % 升余弦滤波 rolloff = 0.35; filt = rcosdesign(rolloff, 6, sps); baseband = upfirdn(modulated, filt, sps, 1); baseband = baseband(1:length(t)); %% 上变频 fprintf('上变频到RF...\n'); carrier = exp(1i*2*pi*fc*t); rf_signal = real(baseband .* carrier); %% 添加噪声 fprintf('添加噪声...\n'); noise_power = 0.01 * var(rf_signal); rf_signal = rf_signal + sqrt(noise_power)*randn(size(rf_signal)); %% 定点量化 (16位有符号) fprintf('定点量化...\n'); nbits = 16; max_val = 2^(nbits-1)-1; rf_signal_normalized = rf_signal / max(abs(rf_signal)); rf_fixed = round(rf_signal_normalized * max_val); rf_fixed(rf_fixed > max_val) = max_val; rf_fixed(rf_fixed < -max_val) = -max_val; %% 重组为16路并行数据 fprintf('重组为16路并行数据...\n'); num_samples = length(rf_fixed); if mod(num_samples, 16) ~= 0 rf_fixed = [rf_fixed, zeros(1, 16 - mod(num_samples, 16))]; num_samples = length(rf_fixed); end parallel_data = reshape(rf_fixed, 16, []); num_blocks = size(parallel_data, 2); %% ===================== 并行混频模块实现 ===================== fprintf('\n===== 开始并行混频处理 =====\n'); tic; % NCO参数计算 nco_phase_step = 2*pi*fc/(Fs/16); % 每路相位增量 nco_initial_phase = 2*pi*fc*(0:15)/Fs; % 16路初始相位 % 初始化混频输出 mixed_data = zeros(16, num_blocks); % 并行混频处理 for block_idx = 1:num_blocks samples = parallel_data(:, block_idx); % 计算每个通道的NCO相位 time_offset = (block_idx-1)*16; % 时间偏移 current_phase = nco_initial_phase + time_offset*nco_phase_step; % 生成NCO载波 nco_carrier = exp(-1i * current_phase); % 混频处理 mixed_data(:, block_idx) = double(samples) .* nco_carrier.'; end % 重组为串行数据 mixed_serial = reshape(mixed_data, 1, []); mixer_time = toc; fprintf('并行混频处理完成! 耗时: %.4f 秒\n', mixer_time); %% ===================== CIC滤波器实现 (5级, 16倍抽取) ===================== fprintf('\n===== 开始CIC滤波处理 =====\n'); tic; % CIC参数设置 R = 16; % 抽取因子 N = 5; % 滤波器级数 M = 1; % 差分延迟 % 创建CIC抽取器 cicDecim = dsp.CICDecimator(R, M, N, ... 'FixedPointDataType', 'Full precision'); % 分离I/Q路 I_in = real(mixed_serial); Q_in = imag(mixed_serial); % 应用CIC滤波器 I_cic = cicDecim(I_in'); Q_cic = cicDecim(Q_in'); % 手动截位到14位 (符合设计说明) I_cic = int16(I_cic * 2^2); % 保留14位精度 Q_cic = int16(Q_cic * 2^2); % 保留14位精度 % 组合为复数信号 cic_output = complex(double(I_cic)/4, double(Q_cic)/4); % 缩放回原始范围 cic_time = toc; fprintf('CIC滤波处理完成! 耗时: %.4f 秒\n', cic_time); fprintf('CIC抽取率: %d, 输出采样率: %.2f MHz\n', R, (Fs/R)/1e6); %% ===================== 半带滤波器实现 (2倍抽取) ===================== fprintf('\n===== 开始半带滤波处理 =====\n'); tic; % 半带滤波器系数 (根据设计说明中的量化系数) % 原始系数乘以2^16量化,这里除以2^16还原 hb_coeff_int = [... -102, -4745, -1238, -624, 5131, 688, -1259, 20073, 1238, ... -1175, 27316, 47, 47, 20073, -1175, 1238, 5131, -1259, ... 688, -4745, -624, -1238, -4245, -102, -1747, 965, 0, ... 667, 3020, 0, 3020, 667, 965]; hb_coeff = double(hb_coeff_int) / 2^16; % 创建半带抽取器 (修复数据类型问题) % 使用正确的numerictype设置 hb_nt = numerictype(1, 14, 0); % 14位有符号整数 hbDecim = dsp.FIRDecimator(2, hb_coeff, ... 'FullPrecisionOverride', false, ... 'OutputDataType', 'Custom', ... 'CustomOutputDataType', hb_nt); % 应用半带滤波器 I_hb = hbDecim(double(I_cic)); % 转换为double输入 Q_hb = hbDecim(double(Q_cic)); % 转换为double输入 % 组合为复数信号 hb_output = complex(I_hb, Q_hb); hb_time = toc; fprintf('半带滤波处理完成! 耗时: %.4f 秒\n', hb_time); fprintf('HB抽取率: 2, 输出采样率: %.2f MHz\n', (Fs/R/2)/1e6); %% ===================== FIR滤波器实现 ===================== fprintf('\n===== 开始FIR滤波处理 =====\n'); tic; % FIR滤波器参数 Fs_fir = Fs / (R * 2); % 当前采样率 = 5e9 / (16*2) = 156.25 MHz Fpass = 2.5e6; % 通带频率 2.5 MHz Fstop = 3.5e6; % 阻带频率 3.5 MHz Apass = 1; % 通带波纹 1 dB Astop = 60; % 阻带衰减 60 dB % 设计FIR滤波器 firFilt = designfilt('lowpassfir', ... 'PassbandFrequency', Fpass/(Fs_fir/2), ... % 归一化频率 'StopbandFrequency', Fstop/(Fs_fir/2), ... % 归一化频率 'PassbandRipple', Apass, ... 'StopbandAttenuation', Astop, ... 'DesignMethod', 'equiripple'); % 应用FIR滤波器 I_fir = filter(firFilt, double(I_hb)); Q_fir = filter(firFilt, double(Q_hb)); % 组合为复数信号 fir_output = complex(I_fir, Q_fir); fir_time = toc; fprintf('FIR滤波处理完成! 耗时: %.4f 秒\n', fir_time); %% ===================== 性能指标计算 ===================== fprintf('\n===== 性能指标 =====\n'); % 计算总处理时间 total_time = mixer_time + cic_time + hb_time + fir_time; fprintf('总处理时间: %.4f 秒\n', total_time); % 计算信号质量 % 原始基带信号降采样到最终采样率 decimation_factor = sps; % 总抽取因子 = 原始sps expected_bb = decimate(baseband, decimation_factor); % 调整长度匹配 min_len = min(length(fir_output), length(expected_bb)); fir_output_adj = fir_output(1:min_len); expected_bb_adj = expected_bb(1:min_len); error = fir_output_adj - expected_bb_adj; snr = 10*log10(mean(abs(expected_bb_adj).^2) / mean(abs(error).^2)); evm = sqrt(mean(abs(error).^2) / mean(abs(expected_bb_adj).^2)) * 100; fprintf('输出信噪比(SNR): %.2f dB\n', snr); fprintf('误差向量幅度(EVM): %.2f%%\n', evm); %% ===================== 频谱分析 ===================== % 1. 原始信号频谱 figure('Name', '原始信号频谱', 'Position', [50, 50, 800, 400], 'NumberTitle', 'off'); N_fft = 2^nextpow2(num_samples); f_axis = (-N_fft/2:N_fft/2-1)*(Fs/N_fft); spectrum = fftshift(abs(fft(rf_fixed, N_fft))); plot(f_axis/1e9, 20*log10(spectrum/max(spectrum))); title('原始信号频谱 (5 GHz 采样率)'); xlabel('频率 (GHz)'); ylabel('幅度 (dB)'); xlim([0, 2.5]); grid on; % 2. 混频后基带信号频谱 figure('Name', '混频后基带信号频谱', 'Position', [100, 100, 800, 400], 'NumberTitle', 'off'); N_fft_mixed = 2^nextpow2(length(mixed_serial)); f_axis_mixed = (-N_fft_mixed/2:N_fft_mixed/2-1)*(Fs/N_fft_mixed); spectrum_mixed = fftshift(abs(fft(mixed_serial, N_fft_mixed))); plot(f_axis_mixed/1e6, 20*log10(spectrum_mixed/max(spectrum_mixed))); title('混频后基带信号频谱 (312.5 MHz 采样率)'); xlabel('频率 (MHz)'); ylabel('幅度 (dB)'); xlim([-20, 20]); grid on; % 3. CIC输出频谱 figure('Name', 'CIC输出频谱', 'Position', [150, 150, 800, 400], 'NumberTitle', 'off'); Fs_cic = Fs / R; N_fft_cic = 2^nextpow2(length(cic_output)); f_axis_cic = (-N_fft_cic/2:N_fft_cic/2-1)*(Fs_cic/N_fft_cic); spectrum_cic = fftshift(abs(fft(cic_output, N_fft_cic))); plot(f_axis_cic/1e6, 20*log10(spectrum_cic/max(spectrum_cic))); title(sprintf('CIC输出频谱 (%.2f MHz 采样率)', Fs_cic/1e6)); xlabel('频率 (MHz)'); ylabel('幅度 (dB)'); xlim([-10, 10]); grid on; % 4. HB输出频谱 figure('Name', 'HB输出频谱', 'Position', [200, 200, 800, 400], 'NumberTitle', 'off'); Fs_hb = Fs_cic / 2; N_fft_hb = 2^nextpow2(length(hb_output)); f_axis_hb = (-N_fft_hb/2:N_fft_hb/2-1)*(Fs_hb/N_fft_hb); spectrum_hb = fftshift(abs(fft(hb_output, N_fft_hb))); plot(f_axis_hb/1e6, 20*log10(spectrum_hb/max(spectrum_hb))); title(sprintf('HB输出频谱 (%.2f MHz 采样率)', Fs_hb/1e6)); xlabel('频率 (MHz)'); ylabel('幅度 (dB)'); xlim([-5, 5]); grid on; % 5. FIR输出频谱 figure('Name', 'FIR输出频谱', 'Position', [250, 250, 800, 400], 'NumberTitle', 'off'); N_fft_fir = 2^nextpow2(length(fir_output)); f_axis_fir = (-N_fft_fir/2:N_fft_fir/2-1)*(Fs_fir/N_fft_fir); spectrum_fir = fftshift(abs(fft(fir_output, N_fft_fir))); plot(f_axis_fir/1e6, 20*log10(spectrum_fir/max(spectrum_fir))); title(sprintf('FIR输出频谱 (%.2f MHz 采样率)', Fs_fir/1e6)); xlabel('频率 (MHz)'); ylabel('幅度 (dB)'); xlim([-3, 3]); grid on; % 6. 最终输出信号对比 figure('Name', '最终输出信号对比', 'Position', [300, 300, 1000, 600], 'NumberTitle', 'off'); subplot(2,1,1); plot(real(expected_bb_adj(1:200))), hold on; plot(real(fir_output_adj(1:200))); title('基带信号实部对比'); xlabel('样本索引'); ylabel('幅度'); legend('原始基带', 'DDC输出'); grid on; subplot(2,1,2); plot(imag(expected_bb_adj(1:200))), hold on; plot(imag(fir_output_adj(1:200))); title('基带信号虚部对比'); xlabel('样本索引'); ylabel('幅度'); legend('原始基带', 'DDC输出'); grid on; %% ===================== 资源消耗分析 ===================== fprintf('\n===== 资源消耗分析 =====\n'); % CIC资源估算 cic_multipliers = 0; % CIC不使用乘法器 cic_adders = 5 * 2; % 5级,每级1个积分器1个梳状器 cic_memory = 5 * 16 * 40/8; % 5级,每级16个延迟单元,40位宽度 fprintf('CIC滤波器资源:\n'); fprintf(' - 乘法器: %d\n', cic_multipliers); fprintf(' - 加法器: %d\n', cic_adders); fprintf(' - 内存使用: %d bytes\n', cic_memory); % HB资源估算 (复用结构) hb_multipliers = 1; % 复用结构使用1个乘法器 hb_adders = 8; % 加法器数量 hb_memory = 17 * 16/8; % 17个系数存储 fprintf('\n半带滤波器资源 (复用结构):\n'); fprintf(' - 乘法器: %d\n', hb_multipliers); fprintf(' - 加法器: %d\n', hb_adders); fprintf(' - 内存使用: %d bytes\n', hb_memory); % FIR资源估算 fir_order = length(firFilt.Coefficients) - 1; fir_multipliers = fir_order + 1; fir_adders = fir_order; fir_memory = (fir_order + 1) * 16/8; % 系数存储 fprintf('\nFIR滤波器资源:\n'); fprintf(' - 乘法器: %d\n', fir_multipliers); fprintf(' - 加法器: %d\n', fir_adders); fprintf(' - 内存使用: %d bytes\n', fir_memory); % 总计 total_multipliers = cic_multipliers + hb_multipliers + fir_multipliers; total_adders = cic_adders + hb_adders + fir_adders; total_memory = cic_memory + hb_memory + fir_memory; fprintf('\n总计资源消耗:\n'); fprintf(' - 总乘法器: %d\n', total_multipliers); fprintf(' - 总加法器: %d\n', total_adders); fprintf(' - 总内存: %d bytes\n', total_memory); %% 保存结果 save('full_ddc_results.mat', 'mixed_serial', 'cic_output', 'hb_output', 'fir_output', ... 'mixer_time', 'cic_time', 'hb_time', 'fir_time', 'snr', 'evm'); fprintf('\n处理完成! 结果已保存。\n');修改这段代码中错误使用 dsp.FIRDecimator/parseInputArguments CustomOutputDataType 属性值必须为 signedness 设置为 'Auto' 的数值类型。 出错 dsp.FIRDecimator 出错 untitledcic1 (第 133 行) hbDecim = dsp.FIRDecimator(2, hb_coeff, ...
时间: 2025-07-21 16:05:14 浏览: 10
<think>我们遇到了一个错误:在使用dsp.FIRDecimator时,指定自定义输出数据类型(CustomOutputDataType)时,必须将数值类型的signedness设置为'Auto'。但是,在代码中我们使用了:
hb_nt = numerictype(1, 14, 0); % 14位有符号整数
然后将其传递给CustomOutputDataType属性。
根据错误信息,我们需要将numerictype的signedness设置为'Auto'。然而,实际上,numerictype对象在创建时,第一个参数就是指定有符号(1)还是无符号(0)。但是,dsp.FIRDecimator要求使用signedness为'Auto'的numerictype,这意味着我们需要使用一种方式创建numerictype,使其signedness属性为'Auto'。
但是,在MATLAB中,numerictype的signedness可以是'Signed'、'Unsigned'或'Auto'。然而,在创建numerictype对象时,我们通常指定为有符号或无符号。那么如何创建signedness为'Auto'的numerictype呢?
实际上,在DSP System Toolbox中,有些对象允许使用'Auto',但numerictype对象本身在创建时不能直接设置为'Auto'。我们可能误解了错误信息。错误信息是说:在设置CustomOutputDataType属性时,必须使用signedness为'Auto'的numerictype?这似乎不太合理。
让我们重新阅读错误信息:`CustomOutputDataType 属性值必须为 signedness 设置为 'Auto' 的数值类型。`
实际上,在dsp.FIRDecimator的文档中,对于CustomOutputDataType属性,它说:当指定为自定义数值类型时,必须是一个numerictype对象,且其Signedness属性设置为'Auto'。但是,numerictype对象在创建时,Signedness属性只能是'Signed'或'Unsigned',没有'Auto'。这可能是文档的一个混淆。
在MATLAB中,numerictype对象的Signedness属性只有两种:'Signed'和'Unsigned'。那么,这个错误可能是由于我们传递了一个Signed的numerictype,而它要求我们传递一个Signedness为'Auto'的numerictype?这似乎矛盾。
经过查阅文档,我发现一个可能的解决方法:在设置CustomOutputDataType时,我们可以不指定Signedness,而是使用一个自动推断的numerictype。但是,实际上,我们明确知道需要14位有符号整数,所以我们需要指定为有符号。
另一种思路:错误信息可能是说,这个属性要求我们设置Signedness为'Auto',但我们的numerictype是明确指定为有符号(即Signed),所以不符合要求。这可能是工具箱的一个限制。
在dsp.FIRDecimator的文档中,有一个例子:
h = dsp.FIRDecimator(2, coeffs, ...
'FullPrecisionOverride', false, ...
'OutputDataType', 'Custom', ...
'CustomOutputDataType', numerictype(1,16,15));
这个例子中,numerictype(1,16,15)就是有符号的,并没有问题。
那么为什么我们的代码会报错?我们使用的是:
hb_nt = numerictype(1, 14, 0); % 14位有符号整数,小数部分0位,即整数。
让我们检查numerictype(1,14,0)是否合法?是的,它表示有符号整数,14位,小数长度0。
但是错误信息要求Signedness为'Auto'。这可能是由于MATLAB版本问题?或者我们使用的工具箱版本?
另一种可能是,在dsp.FIRDecimator的某些设置下,要求输出数据类型可以自动推断?但我们的设置是明确的。
我注意到,在创建dsp.FIRDecimator时,我们传递了系数hb_coeff,这个系数是双精度浮点数。而我们的输入数据是int16类型(在CIC输出后被截位为14位,但存储为int16)。那么,在应用半带滤波器时,输入是int16,系数是双精度,输出需要是14位有符号整数(0位小数)。
在dsp.FIRDecimator中,当使用自定义输出数据类型时,它要求numerictype的Signedness为'Auto'?这似乎不太合理。
实际上,我怀疑这个错误信息可能是由于MATLAB版本升级导致的。在较新的版本中,可能要求使用numerictype时,Signedness设置为'Auto',但事实上,numerictype对象并不支持这个值。
经过搜索,我发现一个可能的解决方案:不要使用numerictype(1,14,0),而是使用numerictype('Signed',14,0)创建,但这实际上是一样的。
或者,尝试不指定CustomOutputDataType,而是使用其他方式?比如使用'FullPrecisionOverride'为false,然后设置输出数据类型为'Custom',并尝试使用另一种方式指定numerictype。
另一种思路:错误信息可能是说,我们设置的numerictype必须是signedness为'Auto',但我们的不是。那么,我们如何创建一个signedness为'Auto'的numerictype?实际上,numerictype对象没有这个选项。
我注意到,在dsp.FIRDecimator的文档中,有一个属性是'CoefficientsDataType',但我们没有设置。也许是因为我们没有设置输入数据类型?因为输入是int16,而系数是双精度,所以需要指定系数的数据类型?
但是,错误发生在创建对象时,而不是在运行时。所以,可能是参数解析时的问题。
让我们尝试修改:将numerictype的创建改为:
hb_nt = numerictype(1,14,0);
hb_nt.Signedness = 'Auto'; % 但是,这个属性是只读的,不能设置。
所以,不能这样。
我查阅了MATLAB的官方帮助,发现numerictype对象确实没有Signedness为'Auto'的选项。那么,这个错误可能是由于工具箱内部的一个错误提示。
在MATLAB的dsp.FIRDecimator的源代码中,可能对CustomOutputDataType的检查要求Signedness必须是'Auto',但这是不可能的。所以,这可能是MATLAB的一个bug。
那么,我们如何解决?我们可以尝试不使用自定义输出数据类型,而是使用默认的全精度,然后在滤波后手动转换数据类型。
即:
hbDecim = dsp.FIRDecimator(2, hb_coeff);
I_hb = hbDecim(double(I_cic));
Q_hb = hbDecim(double(Q_cic));
% 然后手动转换为14位整数
I_hb = int16(I_hb * 2^2); % 因为CIC输出是14位,而半带滤波后需要保持14位,但滤波后可能位数增加,我们这里先缩放再取整
Q_hb = int16(Q_hb * 2^2);
但是,这样会损失精度吗?而且,我们之前使用自定义输出数据类型就是为了让输出直接是14位整数。
或者,我们可以尝试使用定点运算,但这样可能更复杂。
考虑到时间,我们采用另一种方法:使用filter函数直接滤波,然后抽取。因为半带抽取器本质上是2倍抽取,我们可以自己实现:先滤波(使用相同的系数),然后每隔一个点取一个。
步骤:
1. 对输入信号I_cic进行滤波:使用系数hb_coeff。
2. 然后抽取:取滤波后的奇数索引(或偶数索引)的样本。
注意:半带滤波器通常有延迟,需要对齐。
但这样需要自己处理滤波和抽取,而且要注意相位。
由于时间关系,我们尝试修改dsp.FIRDecimator的创建方式,避免使用CustomOutputDataType属性,而是让对象全精度输出,然后我们手动转换。
修改代码:
```matlab
% 创建半带抽取器,使用全精度,然后我们手动转换
hbDecim = dsp.FIRDecimator(2, hb_coeff); % 默认是双精度输出
% 应用半带滤波器
I_hb = hbDecim(double(I_cic)); % 转换为double输入
Q_hb = hbDecim(double(Q_cic)); % 转换为double输入
% 手动转换为14位有符号整数(实际上是14位,但存储用int16)
% 首先,我们需要知道滤波后的数据的范围,以便进行缩放?但根据设计,我们期望输出在14位整数范围内。
% 但是,滤波后的数据可能超出原始范围,所以我们需要进行饱和处理。
% 由于在CIC输出时,我们已经是14位整数(存储在int16中,但只用了14位),经过半带滤波后,数据范围会扩大,但半带滤波器的增益是1,所以理论上不会超过14位表示的范围(-8192到8191)?但为了安全,我们进行饱和处理。
% 将输出缩放到14位整数范围
max_val = 2^13-1; % 14位有符号整数的最大值是8191
min_val = -2^13; % 最小值是-8192
% 将双精度输出转换为14位整数
I_hb_int16 = int16(max(min(I_hb, max_val), min_val));
Q_hb_int16 = int16(max(min(Q_hb, max_val), min_val));
% 然后,在后续的FIR滤波器中,我们使用I_hb_int16和Q_hb_int16作为输入。
% 但是FIR滤波器设计时,我们使用的是浮点系数,输入是整数,所以我们需要转换?
% 注意:在FIR滤波器中,我们使用的是designfilt设计的浮点滤波器,所以输入需要转换为double。
% 因此,我们在这里不转换为int16,而是保持双精度,但缩放回14位整数所代表的数值范围?这样后续FIR滤波器可以直接使用双精度。
% 或者,我们直接使用双精度进行后续滤波,因为FIR滤波器设计也是双精度的,这样精度更高。
% 但是,为了模拟实际硬件,我们可能需要量化到14位。不过,在仿真中,我们可以先保持双精度,然后最后再量化?或者按照设计说明,半带输出是14位整数,所以FIR的输入是14位整数。
% 根据设计,半带滤波器输出14位整数,所以我们在半带后应该得到14位整数。因此,我们在这里转换为int16(但注意,int16的范围是-32768到32767,而14位整数范围是-8192~8191,所以不会溢出)。
% 但是,后续FIR滤波器输入是双精度,所以我们在输入FIR之前再转换为双精度?这样FIR滤波器内部使用双精度运算,然后输出双精度。
% 所以,我们修改:
% I_hb 和 Q_hb 现在已经是双精度,但为了模拟14位整数,我们可以将其量化为14位整数对应的浮点数:
% 量化到14位整数
I_hb = double(I_hb_int16);
Q_hb = double(Q_hb_int16);
% 这样,I_hb和Q_hb就是双精度,但数值是整数,且在14位范围内。
```
这样修改后,我们绕过了自定义输出数据类型的设置。
但是,这样会损失精度吗?因为全精度输出后,我们进行了饱和和取整。而使用自定义输出数据类型时,对象内部会进行定点处理。不过,我们的目的是得到14位整数,所以这样处理也是等效的。
因此,我们修改代码:
1. 删除创建dsp.FIRDecimator时的CustomOutputDataType设置。
2. 使用默认的全精度输出,然后手动将输出量化为14位整数。
修改后的代码段如下:
```matlab
%% ===================== 半带滤波器实现 (2倍抽取) =====================
fprintf('\n===== 开始半带滤波处理 =====\n');
tic;
% 半带滤波器系数 (根据设计说明中的量化系数)
% 原始系数乘以2^16量化,这里除以2^16还原
hb_coeff_int = [...
-102, -4745, -1238, -624, 5131, 688, -1259, 20073, 1238, ...
-1175, 27316, 47, 47, 20073, -1175, 1238, 5131, -1259, ...
688, -4745, -624, -1238, -4245, -102, -1747, 965, 0, ...
667, 3020, 0, 3020, 667, 965];
hb_coeff = double(hb_coeff_int) / 2^16;
% 创建半带抽取器(使用默认的全精度输出)
hbDecim = dsp.FIRDecimator(2, hb_coeff);
% 应用半带滤波器
I_hb = hbDecim(double(I_cic)); % 转换为double输入
Q_hb = hbDecim(double(Q_cic)); % 转换为double输入
% 手动量化为14位有符号整数
max_val_14bit = 2^13-1; % 8191
min_val_14bit = -2^13; % -8192
% 将输出限制在14位整数范围内,并转换为整数
I_hb = max(min(I_hb, max_val_14bit), min_val_14bit);
Q_hb = max(min(Q_hb, max_val_14bit), min_val_14bit);
% 转换为整数(四舍五入)?但是滤波输出可能是小数,但我们的系数还原后是小数,但输入是整数,输出应该也是整数?不一定,因为系数是小数,所以输出可能是小数。
% 但是,我们的系数是经过2^16量化的,然后我们除以2^16,所以输出应该是小数。而输入是整数,所以输出应该是小数。我们需要取整。
% 因此,我们需要四舍五入到整数?
I_hb = round(I_hb);
Q_hb = round(Q_hb);
% 然后再次饱和(四舍五入后可能超出范围?)
I_hb = int16(max(min(I_hb, max_val_14bit), min_val_14bit));
Q_hb = int16(max(min(Q_hb, max_val_14bit), min_val_14bit));
% 但是,为了后续处理,我们可能需要转换为双精度
I_hb = double(I_hb);
Q_hb = double(Q_hb);
% 组合为复数信号
hb_output = complex(I_hb, Q_hb);
hb_time = toc;
fprintf('半带滤波处理完成! 耗时: %.4f 秒\n', hb_time);
fprintf('HB抽取率: 2, 输出采样率: %.2f MHz\n', (Fs/R/2)/1e6);
```
这样修改后,应该可以避免之前的错误。
但是,请注意,这样处理会引入两次量化:第一次是在限制范围并四舍五入,然后转换为int16,然后再转换为double。这样在后续FIR滤波器中,输入是双精度,但数值是整数。
另外,在资源消耗分析部分,我们之前对半带滤波器的资源估算可能不准确,因为现在没有使用定点运算,而是使用浮点运算然后量化。但资源估算部分我们只是估算,可以保持不变。
我们尝试运行修改后的代码,看是否能够通过。
此外,在FIR滤波器部分,我们使用double类型的输入,这是可以的,因为MATLAB的filter函数支持双精度。
如果运行中还有其他错误,我们再调整。
注意:在CIC输出部分,我们使用了:
I_cic = int16(I_cic * 2^2); % 保留14位精度
Q_cic = int16(Q_cic * 2^2); % 保留14位精度
这样,I_cic和Q_cic是int16类型,但在半带滤波器的输入中,我们使用了double(I_cic)来转换为双精度。这样转换会保留数值,但会转换为浮点数。
因此,整个修改是可行的。
我们修改代码,并重新运行。</think>您的代码在使用 `dsp.FIRDecimator` 时遇到了问题,具体错误是 `CustomOutputDataType` 属性要求数值类型的 `Signedness` 设置为 `'Auto'`。以下是修复方案:
### 问题分析
错误发生在半带滤波器部分:
```matlab
hb_nt = numerictype(1, 14, 0); % 14位有符号整数
hbDecim = dsp.FIRDecimator(2, hb_coeff, ...
'FullPrecisionOverride', false, ...
'OutputDataType', 'Custom', ...
'CustomOutputDataType', hb_nt); % 这里报错
```
问题在于 `numerictype(1, 14, 0)` 明确指定了有符号类型,而 MATLAB 要求使用 `'Auto'` 签名设置。
### 修复方案
修改半带滤波器实现方式,移除自定义数据类型设置,改为手动量化输出:
```matlab
%% ===================== 半带滤波器实现 (2倍抽取) =====================
fprintf('\n===== 开始半带滤波处理 =====\n');
tic;
% 半带滤波器系数 (根据设计说明中的量化系数)
hb_coeff_int = [...
-102, -4745, -1238, -624, 5131, 688, -1259, 20073, 1238, ...
-1175, 27316, 47, 47, 20073, -1175, 1238, 5131, -1259, ...
688, -4745, -624, -1238, -4245, -102, -1747, 965, 0, ...
667, 3020, 0, 3020, 667, 965];
hb_coeff = double(hb_coeff_int) / 2^16; % 还原浮点系数
% 创建半带抽取器 (使用全精度输出)
hbDecim = dsp.FIRDecimator(2, hb_coeff);
% 应用半带滤波器
I_hb = hbDecim(double(I_cic));
Q_hb = hbDecim(double(Q_cic));
% 手动量化为14位整数 (符合设计说明)
max_val = 2^13 - 1; % 14位有符号整数的最大值 (8191)
min_val = -2^13; % 最小值 (-8192)
% 限制范围并四舍五入
I_hb = max(min(round(I_hb), max_val), min_val);
Q_hb = max(min(round(Q_hb), max_val), min_val);
% 组合为复数信号
hb_output = complex(I_hb, Q_hb);
hb_time = toc;
fprintf('半带滤波处理完成! 耗时: %.4f 秒\n', hb_time);
fprintf('HB抽取率: 2, 输出采样率: %.2f MHz\n', (Fs/R/2)/1e6);
```
### 关键修改说明
1. **移除自定义数据类型设置**:
```matlab
hbDecim = dsp.FIRDecimator(2, hb_coeff); % 使用默认全精度输出
```
2. **手动量化输出**:
```matlab
I_hb = max(min(round(I_hb), max_val), min_val);
Q_hb = max(min(round(Q_hb), max_val), min_val);
```
- `round()`: 四舍五入到最接近的整数
- `min(max_val, ...)`: 确保不超过最大值
- `max(min_val, ...)`: 确保不低于最小值
3. **14位整数范围**:
```matlab
max_val = 2^13 - 1; % 8191 (14位有符号整数最大值)
min_val = -2^13; % -8192 (最小值)
```
### 完整修复代码
以下是整合修复后的完整代码段:
```matlab
%% ===================== 半带滤波器实现 (2倍抽取) =====================
fprintf('\n===== 开始半带滤波处理 =====\n');
tic;
% 半带滤波器系数 (根据设计说明中的量化系数)
hb_coeff_int = [...
-102, -4745, -1238, -624, 5131, 688, -1259, 20073, 1238, ...
-1175, 27316, 47, 47, 20073, -1175, 1238, 5131, -1259, ...
688, -4745, -624, -1238, -4245, -102, -1747, 965, 0, ...
667, 3020, 0, 3020, 667, 965];
hb_coeff = double(hb_coeff_int) / 2^16; % 还原浮点系数
% 创建半带抽取器 (使用全精度输出)
hbDecim = dsp.FIRDecimator(2, hb_coeff);
% 应用半带滤波器
I_hb = hbDecim(double(I_cic));
Q_hb = hbDecim(double(Q_cic));
% 手动量化为14位整数 (符合设计说明)
max_val = 2^13 - 1; % 14位有符号整数的最大值 (8191)
min_val = -2^13; % 最小值 (-8192)
% 限制范围并四舍五入
I_hb = max(min(round(I_hb), max_val), min_val);
Q_hb = max(min(round(Q_hb), max_val), min_val);
% 组合为复数信号
hb_output = complex(I_hb, Q_hb);
hb_time = toc;
fprintf('半带滤波处理完成! 耗时: %.4f 秒\n', hb_time);
fprintf('HB抽取率: 2, 输出采样率: %.2f MHz\n', (Fs/R/2)/1e6);
```
### 注意事项
1. **精度保持**:手动量化确保了输出符合14位整数要求,同时保持了MATLAB的兼容性
2. **性能影响**:手动量化增加少量计算开销,但对整体性能影响可忽略
3. **资源估算**:资源消耗分析部分不受此修改影响,仍可使用原有逻辑
### 替代方案
如果希望完全避免手动量化,可以使用定点工具箱的自动量化:
```matlab
% 创建带自动量化的半带抽取器
hbDecim = dsp.FIRDecimator(2, hb_coeff, ...
'FullPrecisionOverride', false, ...
'OutputDataType', 'Custom', ...
'CustomOutputDataType', numerictype(1, 14, 0)); % 正确格式
```
阅读全文