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

一、参考文章:

重采样、上采样、下采样 - 知乎 (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); % 归一化LPFA = 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==

结果:

还是文章一,插值可以用另一种方法,即,不是插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:N2if(m==800)m=800;endseq_begin = floor(M*m/N) - INF_L + 1;if(seq_begin<1)seq_begin=1;endseq_end = floor(M*m/N) + INF_L;if(seq_end>N1)seq_end=N1;endfor n=seq_begin:seq_endtmp = abs(M*m - N*n)+1;sig_out(m) = sig_out(m) + sig(n)*sin(pi*tmp/M)./(pi*tmp/M);end    
endsig_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;

结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/645880.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

libjsoncpp 的编译和交叉编译

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

开通商家转账到零钱技巧

商家转账到零钱是什么&#xff1f; 通过商家转账到零钱这个功能&#xff0c;如果我们系统需要对用户支付费用&#xff0c;比如发放佣金、提成、退款之类的&#xff0c;可以直接转账到用户的微信零钱。 【商家转账到零钱】是【企业付款到零钱】的升级版&#xff0c;2022年5月1…

H264解码原理详解

H.264的编码原理参考文章H.264的编码原理 解码原理 解码器负责将符合H.264码流规范的压缩视频流解码&#xff0c;并进行图像重建。 根据如下图所示的解码器流图&#xff0c;我们可以看出基本的解码流程如下&#xff1a;解码器从网络提取层中接收压缩的比特流&#xff0c;经过…

Mysql复习1--理论基础+操作实践--更新中

Mysql 索引索引的分类索引失效sql优化 删除数据库数据恢复 索引InnoDB引擎MyISAM引擎Memory引擎Btree索引支持支持支持hash索引不支持不支持支持R-tree索引不支持支持不支持Full-text索引5.6版本以后支持支持不支持 索引 解释说明: 索引指的是帮助mysql高效的获取数据的结构叫…

《Windows核心编程》若干知识点实战应用分享

目录 1、进程的虚拟内存分区与小于0x10000的小地址内存区 1.1、进程的虚拟内存分区 1.2、小于0x10000的小地址内存区 2、保存线程上下文的CONTEXT结构体 3、从汇编代码角度去理解多线程运行过程的典型实例 4、调用TerminateThread强制结束线程会导致线程中的资源没有释放…

Redisson 分布式锁可重入的原理

目录 1. 使用 Redis 实现分布式锁存在的问题 2. Redisson 的分布式锁解决不可重入问题的原理 1. 使用 Redis 实现分布式锁存在的问题 不可重入&#xff1a;同一个线程无法两次 / 多次获取锁举例 method1 执行需要获取锁method2 执行也需要&#xff08;同一把&#xff09;锁如…

Python map函数

在Python编程中&#xff0c;map()函数是一个强大的工具&#xff0c;用于将函数应用于可迭代对象&#xff08;如列表、元组等&#xff09;的每个元素&#xff0c;然后返回一个新的可迭代对象&#xff0c;其中包含应用函数后的结果。本文将深入探讨map()函数的用法&#xff0c;提…

云计算项目五:部署数据库服务mysql |部署共享存储服务NFS | 配置网站服务

部署数据库服务mysql |部署共享存储服务NFS | 配置网站服务 案例1:配置逻辑卷步骤一:创建LV步骤二:格式化案例2:配置数据库服务器步骤一:安装软件MySQL服务软件(2台数据库服务器都要安装)步骤二:挂载lv设备步骤三:启动服务步骤四:管理员登录案例3:配置主从同步步骤一…

linuxshell日常脚本命令之if判断

shell脚本if中判断大于、小于、等于、不等于的符号 脚本有问题&#xff0c;有没有哪位大佬能帮忙检查一下&#xff1f; #!/bin/bash#run_num$(squeue | grep shifting | wc -l) run_numsqueue | grep shifting | wc -l #run_num$(squeue | grep shifting | wc -l 2>&1…

vue+draggable+el-upload上传图片拖拽重排方法

vuedraggableel-upload上传图片拖拽重排方法 1.html <el-row><el-col><el-form-item label"添加视频/图片" prop"device_id"><div class"image-upload"><draggable v-model"fileList" update"dataDr…

js树形控件zTree使用总结

文章目录 一、zTree简介1.1、zTree的特点1.2、zTree文件介绍 二、zTree的基本使用2.1、zTree的创建2.2、zTree的配置2.3、zTree的数据格式2.3.1、标准数据格式2.3.2、简单数据格式 2.4、zTree的常用方法2.4.1、获取zTree对象2.4.2、增加节点2.4.3、勾选或取消勾选全部节点2.4.4…

视频汇聚/云存储平台EasyCVR级联上级播放后一直发流是什么原因?

可视化云监控平台/安防视频监控系统EasyCVR视频综合管理平台&#xff0c;采用了开放式的网络结构&#xff0c;可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联、磁盘阵列存储、视频集中存储、云存储等丰富的视频能力&#xff0c;同时…

【Web前端实操12】将一个100*100的盒子,变成圆形

将一个100*100的盒子&#xff0c;变成圆形&#xff0c;是一个简单的实操&#xff0c;想要完成这个实操&#xff0c;最关键的是一个知识点&#xff0c;使用 CSS3 border-radius 属性&#xff0c;你可以给任何元素制作 "圆角" border-radius 属性&#xff0c;可以使用…

软考复习之软件工程篇

软件生命周期 问题定义&#xff1a;要示系统分析员与用户进行交流&#xff0c;弄清”用户需要计算机解决什么问题”然后提出关于“系统目标与范围的说明”&#xff0c;提交用户审查和确认 可行性研究&#xff1a;一方面在于把待开发的系统的目标以明确的语言描述出来&#xf…

【Linux】shell外壳和权限

文章目录 shell外壳用户切换权限 shell外壳 什么是shell外壳呢&#xff1f;首先我们应该知道&#xff0c;用户和操作系统内核是不能直接接触的&#xff0c;因为首先操作系统本身就很难去操作&#xff0c;另一方面也是为了操作系统安全考虑&#xff0c;不能让用户直接去操作内核…

JeecgBoot 3.6.1实现Modal对话框,以为审核数据为例

JeecgBoot 3.6.1实现Modal对话框 vue使用的是3.0版本 文章目录 JeecgBoot 3.6.1实现Modal对话框前言一、列表页面关键代码示例二、textAuditModal.vue代码示例三、test.api.ts总结 前言 在工作中&#xff0c;有一个需求&#xff0c;要求&#xff0c;在数据列表页&#xff0c;…

SUBMIT指定用户名错误

1、SUBMIT说明 在ABAP中&#xff0c;SUBMIT关键字用于运行另一个ABAP程序。通过SUBMIT关键字&#xff0c;可以在当前程序内部调用其他程序&#xff0c;而无需关闭当前程序。 SUBMIT语句的一般语法如下&#xff1a; "--------------------斌将军-------------------- SUB…

Java接收curl发出的中文请求无法解析

最近做项目遇到了这种情况&#xff0c;Java接收curl发出的中文请求无法解析&#xff0c;英文请求一切正常&#xff0c;中文请求则对方服务器无法解析&#xff0c;可以猜测是中文导致的编码问题&#xff0c;但是奇怪的是&#xff0c;本地输出json也没有乱码&#xff0c;编解码正…

leetcode:三数之和---双指针

问题&#xff1a; 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复…

bean的一生

你曾读spring源码 “不知所云”、“绞尽脑汁”、“不知所措”嘛&#x1f923;&#x1f923;&#x1f923; 那这篇文章可能会对你有所帮助&#xff0c;小编尝试用简单、易懂的例子来模拟spring经典代码&#x1f449;Spring Bean生命周期及扩展点&#xff0c; 让你能够****轻松…