手撕重采样,考虑C的实现方式

您所在的位置:网站首页 c语言实现插值 手撕重采样,考虑C的实现方式

手撕重采样,考虑C的实现方式

2024-07-14 09:25| 来源: 网络整理| 查看: 265

一、参考文章:

重采样、上采样、下采样 - 知乎 (zhihu.com)

先直接给结论,正常重采样过程如下:

1、对于原采样率fs,需要重采样到fs1,一般fs和fs1都是整数哈,则先找fs和fs1的最小公倍数,设为m,设m/fs=M,m/fs1 = L。则信号先要做M倍的插值,即上采样,再做1/L倍的抽取,即下采样;

2、因为插值和抽取,信号的频带都会变,也就是信号会引入噪声,所以需要滤波处理;

3、具体来说,插值,频谱变窄,即信号频带压缩了,如果不做处理,信号会包含带宽以外的噪声,所以需要做低通只滤出变窄的信号频带,去掉噪声。抽取,之后的频谱会变宽,即最终和原信号频谱对不上,所以又需要低通滤波,将信号滤到和原信号一样的频带。

4、具体来说,第一个低通的通带(归一化)是0~1/M,第二个低通的通带是0~1/L。找到满足性能的滤波器,还是比较有考验的。

回到程序,上文中第一段,涉及到滤波器,改用0相位滤波,即调用matlab的filtfilt。滤波时考虑使用原程序中的滤波器幅值归一化。且,加入抽取、滤波,即实现重采样完整流程,最后,还对比matlab自己的resample函数结果。如下:

clc; close all; clear all; %%%%%%%%%%%%%%%%%程序说明 % 1、使用'zero stuffing'和'low pass filter'实现内插/上采样 N = 4; % 上采样率 h_t = ones(1, N); h_t_lp = sinc(-pi:2*pi/20:pi); % h_t_lp = h_t_lp ./ sum(h_t_lp); % 归一化LPF A = 1.5; B = 1; f1 = 50; f2 = 100; Fs = 1000; t = 0:1/Fs:1; sig = A * cos(2 * pi *f1 * t) + B * sin(2 * pi *f2 * t); % 原始数据 % 插值:插入0 sig_zerostuff = zeros(1, length(sig) * N); sig_zerostuff(1 : N : length(sig_zerostuff)) = sig; sig_zerostuff_lp = conv(sig_zerostuff, h_t_lp); % 采样保持:使得插入的数值与原数据的数值一致 sig_sample_hold = conv(sig_zerostuff, h_t); % 将采样保持的信号经过LPF h_t_lp = h_t_lp ./ sum(h_t_lp); % 归一化LPF % sig_sample_hold_lp = conv(sig_sample_hold, h_t_lp); sig_sample_hold_lp = filtfilt(h_t_lp,1,sig_sample_hold); subplot(5,1,1); stem(sig,'MarkerFaceColor',[0 0 1]);xlim([1 25]); title('原始数据'); subplot(5,1,2); stem(sig_zerostuff,'MarkerFaceColor',[1 0 0]);xlim([1 25*N]); title('插值后的数据'); subplot(5,1,3); stem(sig_zerostuff_lp,'MarkerFaceColor',[1 0 0]);xlim([1 25*N]); title('插值后的数据通过LPF'); subplot(5,1,4); stem(sig_sample_hold,'MarkerFaceColor',[1 0 0]);xlim([1 25*N]); title('插值保持后的数据'); subplot(5,1,5); stem(sig_sample_hold_lp,'MarkerFaceColor',[1 0 0]);xlim([1 25*N]); title('采样保持的数据通过LPF'); % 抽取,1/3 sig_sample_hold_lp_downsample = sig_sample_hold_lp(1:3:end); % sig_sample_hold_lp_downsample_lp = conv(sig_sample_hold_lp_downsample, h_t_lp); sig_sample_hold_lp_downsample_lp = filtfilt(h_t_lp,1,sig_sample_hold_lp_downsample); sig_resample = resample(sig, 4, 3); figure subplot(4,1,1); stem(sig,'MarkerFaceColor',[0 0 1]);xlim([1 120]); title('原始数据'); subplot(4,1,2); stem(sig_sample_hold_lp_downsample,'MarkerFaceColor',[0 1 0]);xlim([1 120]); title('抽取数据'); subplot(4,1,3); stem(sig_sample_hold_lp_downsample_lp,'MarkerFaceColor',[1 0 0]);xlim([1 120]); title('抽取数据通过LPF'); subplot(4,1,4); stem(sig_resample,'MarkerFaceColor',[0 0 0]);xlim([1 120]); title('resample重采样数据');

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

结果:

还是文章一,插值可以用另一种方法,即,不是插0值或者保持,而是用其他插值法,matlab有interp函数,可以设置参数用不同插值法。典型的线性插值,应该比较好找C代码。

先看看文章的效果:

效果还是可以的。

关于线性插值C代码,时间关系暂未验证哈:

线性插值_c语言实现_线性插值c语言程序-CSDN博客

标准C语言插值函数 - 百度文库 (baidu.com)

二、一种自创的简单、近似算法

应该有很多这样使用的,只是介绍的少,属于私下处理算法。

简单来说,思路是:

考查原始信号时间点和重采样后信号的时间点,一般来说,重采样信号的一个时间点,是处在原始信号的两个信号点之间(若重合,则直接不用计算),根据此时间点到原信号两个信号点的距离,用原信号这两个信号点插值得到重采样信号此点的信号幅值。

所以很明显,这种方法的优点是,不用考虑抽取、插值、滤波这些麻烦事,只考虑插值即可。

但是,缺点也有,就是不能统一处理,必须每个点都分别处理。

时间关系,后续,可以再测试下。

三、查到一个专利,但是算法还是有问题,未程序实现:

CN202010258902一种数字信号的任意重采样方法及系统

无法添加附件,是个问题。

主要步骤有:

简单说是用sinc函数实现。但是还有较多看不懂的。感觉不理解0052到0058的用意是啥。但是貌似,可以不管其他,直接用最后一个公式算就行了......

后续试试程序仿真...

有关sinc函数(也较辛格函数):20211003:数字滤波器前置知识,sinc函数与Sa函数_sinc函数与sa函数区别-CSDN博客

程序仿真来了,但是结果好像不对,不知道是这理论有问题还是哪里理解不对,欢迎交流了:

clc; clear all; close all; A = 1.5; B = 1; f1 = 50; f2 = 100; Fs = 1000; t = 0:1/Fs:1; sig = A * cos(2 * pi *f1 * t) + B * sin(2 * pi *f2 * t); % 原始数据 M = 4; % 上采样率 N = 3; % Fs1/Fs = M/N INF_L = 50; N1 = length(sig); N2 = floor(N1*M/N); sig_out = zeros(1,N2); for m=1:N2 if(m==800) m=800; end seq_begin = floor(M*m/N) - INF_L + 1; if(seq_beginN1) seq_end=N1; end for n=seq_begin:seq_end tmp = abs(M*m - N*n)+1; sig_out(m) = sig_out(m) + sig(n)*sin(pi*tmp/M)./(pi*tmp/M); end end sig_out2 = resample(sig,4,3); subplot(3,1,1); stem(sig,'MarkerFaceColor',[1 0 0]);xlim([1 100]); title('原数据'); subplot(3,1,2); stem(sig_out,'MarkerFaceColor',[1 1 0]);xlim([1 100]); title('sinc重采样数据'); subplot(3,1,3); stem(sig_out2,'MarkerFaceColor',[1 0 1]);xlim([1 100]); title('resample重采样数据'); zhh = 1;

结果:

尝试将resample语句改为:resample(sig,3,4),好像相位对上了,只是赋值差一些。难道是原专利比例写反了:

四、其他,测试matlab上采样、下采样的程序: clc; clear all; close all; fs = 10; t1 = 0:1/fs:1; x = t1; y = resample(x,3,2); t2 = (0:(length(y)-1))*2/(3*fs); plot(t1,x,'*',t2,y,'o') xlabel('Time (s)') ylabel('Signal') legend('Original','Resampled', ... 'Location','NorthWest') %创建一个原始信号 t = linspace(0,1,1000); y = sin(2*pi*10*t) ; %测试升采样 y_resampled = resample(y,2,1); y_upsampled = upsample(y,2); %绘制原始信号和重采样后的信号 figure subplot(3,1,1); % stem(t,y);xlim([1 100]) stem(y);xlim([1 100]) title('Original Signal'); subplot(3,1,2); % t_resampled = linspace(0,1,length(y_resampled)); stem(y_resampled);xlim([1 100]) title('Resampled Signal'); subplot(3,1,3); % t_y_upsampled = linspace(0,1,length(y_upsampled)); stem(y_upsampled);xlim([1 100]) title('upsampled Signal'); % 测试降采样 y_resampled = resample(y,1,2); y_downsampled = downsample(y,2); y_decimated = decimate(y,2); %绘制原始信号和重采样后的信号 figure subplot(3,1,1); % stem(t,y);xlim([1 100]) stem(y);xlim([1 100]) title('Original Signal'); subplot(3,1,2); % t_resampled = linspace(0,1,length(y_resampled)); stem(y_resampled);xlim([1 100]) hold on;stem(y_downsampled,'MarkerFaceColor','r');xlim([1 100]) legend('y\_resampled','y\_downsampled'); title('downsampled Signal'); subplot(3,1,3); % t_y_downsampled = linspace(0,1,length(y_downsampled)); stem(y_resampled);xlim([1 100]) hold on;stem(y_decimated,'MarkerFaceColor','y');xlim([1 100]) legend('y\_resampled','y\_decimated'); title('decimated Signal');



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3