RF信号下采样/矩阵下采样(附python实现代码)

之前对于RF信号下采样这个问题特别的懵,上采样我是知道的,其中一种方法就是对于矩阵插值,使得它具有更多的信息。

但是下采样,我查了很多资料,在知网上看到一篇论文(好像不是计算机领域的),他对于矩阵下采样就是删除特定的列和行,比如是8 * 8的矩阵,那就删除2 4 6 8列和行,得到一个含1 3 5 7列和行的4 * 4大小的矩阵。

上周开了组会,刚好听一个很厉害的师兄在查新汇报中说到了RF信号下采样的问题,我就去请教了师兄,啊,其实,很简单呐,就是卷积,比如卷积核大小是3 * 3,那就可以让一个5 * 5大小的矩阵变为3 * 3大小的。

嗯……所以,我对卷积这方面还不是很熟悉,我要去详细的学习一下卷积的相关内容~~~

一、卷积是什么呢?

卷积(又名褶积)和反卷积(又名反褶积)是一种积分变换的数学方法。

卷积是分析数学中一种重要的运算。
简单定义:设: f(x),g(x)是R1上的两个可积函数,作积分:
在这里插入图片描述

可以证明,关于几乎所有的实数 x,上述积分是存在的。这样,随着 x 的不同取值,这个积分就定义了一个新函数,称为函数与的卷积,记为:
在这里插入图片描述

容易验证,并且仍为可积函数。这就是说,把卷积代替乘法,L1(R1)空间是一个代数,甚至是巴拿赫代数。

由卷积得到的函数一般要比和都光滑。特别当为具有紧致集的光滑函数,为局部可积时,它们的卷积也是光滑函数。利用这一性质,对于任意的可积函数,都可以简单地构造出一列逼近于的光滑函数列,这种方法称为函数的光滑化或正则化

卷积是两个变量在某范围内相乘后求和的结果。如果卷积的变量是序列和,则卷积的结果:
在这里插入图片描述

其中星号*表示卷积。当时序时,序列是的时序 i 取反的结果;时序取反使得以纵轴为中心翻转180度,所以这种相乘后求和的计算法称为卷积和,简称卷积。另外,是使位移的量,不同的对应不同的卷积结果。

如果卷积的变量是函数和,则卷积的计算变为:
在这里插入图片描述

其中p是积分变量,积分也是求和,t是使函数h(-p)位移的量,星号*表示卷积。

好了,以上是百度百科的内容。也算是对于卷积有了一个初步的理解了~~

二、如何卷积

然后,我们就要看看,要怎么卷积

对卷积这个名词的理解:所谓两个函数的卷积,本质上就是先将一个函数翻转,然后进行滑动叠加

在连续情况下,叠加指的是对两个函数的乘积求积分,在离散情况下就是加权求和,为简单起见就统一称为叠加。整体看来是这么个过程:

翻转——>滑动——>叠加——>滑动——>叠加——>滑动——>叠加…多次滑动得到的一系列叠加值,构成了卷积函数

卷积的“”,指的的函数的翻转,从 g(t) 变成 g(-t) 的这个过程;卷积的“”,指的是积分/加权求和

三、理解图像中的矩阵

图像可以表示为矩阵的形式
在这里插入图片描述
对图像的处理函数(如平滑,或者边缘提取),也可以用一个 g 矩阵来表示,如:
在这里插入图片描述
注意,我们在处理平面空间的问题,已经是二维函数了,相当于:
在这里插入图片描述
在这里插入图片描述
那么函数 f 和 g 的在(u,v)处的卷积 [公式] 该如何计算呢?
按卷积的定义,二维离散形式的卷积公式应该是:
在这里插入图片描述
从卷积定义来看,应该是在 x 和 y 两个方向去累加(对应上面离散公式中的 i 和 j 两个下标),而且是无界的,从负无穷到正无穷。可是,真实世界都是有界的。例如,上面列举的图像处理函数 g 实际上是个3 * 3的矩阵,意味着,在除了原点附近以外,其它所有点的取值都为0。考虑到这个因素,上面的公式其实退化了,它只把坐标(u,v)附近的点选择出来做计算了。所以,真正的计算如下所示:
在这里插入图片描述
​​首先我们在原始图像矩阵中取出(u,v)处的矩阵:
在这里插入图片描述
然后将图像处理矩阵翻转(这个翻转有点意思,可以有几种不同的理解,其效果是等效的:(1)先沿x轴翻转,再沿y轴翻转;(2)先沿x轴翻转,再沿y轴翻转;),如下:
原始矩阵:
在这里插入图片描述
翻转后的矩阵:
在这里插入图片描述
计算卷积时,就可以用 f 和 g’ 的内积:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
以上公式有一个特点,做乘法的两个对应变量a,b的下标之和都是(u,v),其目的是对这种加权求和进行一种约束。

以上计算的是**(u,v)处的卷积**,沿x轴或者y轴滑动,就可以求出图像中各个位置的卷积,其输出结果是处理以后的图像(即经过平滑、边缘提取等各种处理的图像)。

如下图像处理矩阵将使得图像变得更为平滑,显得更模糊,因为它联合周边像素进行了平均处理:
在这里插入图片描述
而如下图像处理矩阵将使得像素值变化明显的地方更为明显,强化边缘,而变化平缓的地方没有影响,达到提取边缘的目的:
在这里插入图片描述

四、卷积核大小、个数,卷积层数如何确定?

在达到相同感受野的情况下,卷积核越小,所需要的参数和计算量越小。具体来说。卷积核大小必须大于1才有提升感受野的作用,1排除了。而大小为偶数的卷积核即使对称地加padding也不能保证输入feature map尺寸和输出feature map尺寸不变(画个图算一下就可以发现),2排除了。所以一般都用3作为卷积核大小

每一层卷积有多少channel数,以及一共有多少层卷积,这些暂时没有理论支撑,一般都是靠感觉去设置几组候选值,然后通过实验挑选出其中的最佳值。这也是现在深度卷积神经网络虽然效果拔群,但是一直为人诟病的原因之一。

五、对RF信号进行下采样

图像下采样原理:
对于一幅图像 I 尺寸为M * N,对其进行 s 倍下采样,即得到(M/s) * (N/s)尺寸的得分辨率图像,当然 s 应该是 M 和 N 的公约数才行,如果考虑的是矩阵形式的图像,就是把原始图像s * s窗口内的图像变成一个像素,这个像素点的值就是窗口内所有像素的均值:
在这里插入图片描述
那么如果图像按列向量化,变成了1*(MN)的向量之后,这个下采样过程也应当有一个对应的矩阵,这个矩阵的大小为(MN/s^2)*(MN)。

那么对RF信号进行下采样就等于对矩阵下采样,比如我的RF信号矩阵是处理为了 200 * 200 大小的,那么对它下4采样就是得到 50 * 50 大小的矩阵。

现在的问题就是 如何确定卷积核的大小和数值???

好了,搜了很久卷积核的数值都没找到,然后发现那个东西叫算子!!!而且,有一些常用的算子,是可以直接用的有个sobel?效果蛮好的。

一些常用的卷积核:
在这里插入图片描述
在这里插入图片描述
Sobel 算子为例

Sobel 算子 也叫 Sobel 滤波, 是两个 3*3 的矩阵,主要用来计算图像中某一点在横向/纵向上的梯度,看了不少网络上讲解 Sobel 算子 的文章,发现人们常常把它的横向梯度矩阵和纵向梯度矩阵混淆。这可能与 Sobel 算子 在它的两个主要应用场景中的不同用法有关。

Sobel 算子的两个梯度矩阵: Gx 和 Gy

这里以 Wiki 资料为准,Sobel 算子有两个滤波矩阵:Gx 和 Gy, Gx 用来计算横向的梯度,Gy 用来计算纵向的梯度, 下图就是具体的滤波器:
在这里插入图片描述
Sobel 算子的用途:

它可以用来对图像进行边缘检测,或者用来计算某个像素点的法线向量。这里需要注意的是:

边缘检测时:Gx 用于检测纵向边缘,Gy 用于检测横向边缘。

计算法线时:Gx 用于计算法线的横向偏移,Gy 用于计算法线的纵向偏移。

横向新值 = (-1) * [左上] + (-2) * [左] + (-1) * [左下] + 1 * [右上] + 2*[右] + 1*[右下]

纵向新值 = (-1) * [左上] + (-2) * [上] + (-1)[右] + 1 * [左下] + 2[下] + 1*[右下]

卷积核的个数对应输出通道,每个卷积核的通道对应输入的通道数

六、实战处理

首先是运用Sobel算子,对于mat文件(也就是矩阵形式)进行一个卷积,mat文件是200 * 200大小的矩阵,算子是3 * 3的,运用以下代码,得到了200 * 200大小的卷积后的矩阵:

对于mat文件的相关操作见 此处

import numpy as np
import scipy.io as scio #读取mat文件所用的包

dataFile = 'K://数据集/train/00001/1/1.mat' #mat数据地址

def zero_pad(x, pad_height, pad_width):# 先在待处理矩阵周围填充0

    H, W = x.shape# H为待处理矩阵的高(行),Wi为待处理矩阵的宽(列)
    out = None
    out = np.zeros((H+2*pad_height, W+2*pad_width))# 知道尺寸后先全填入0
    out[pad_height:pad_height+H, pad_width:pad_width+W] = x# 后在中间填入x,这样边缘填充0就完成了
    return out


def conv_fast(x, h):

    Hi, Wi = x.shape# Hi为待处理矩阵的高(行),Wi为待处理矩阵的宽(列)
    Hh, Wh = h.shape# Hh为卷积核的高(行),Wi为卷积的宽(列)
    out = np.zeros((Hi, Wi))# 相当于占位

    pad_height = Hh // 2   #mode为same情况下,填充0的数量取决于卷积核h的尺寸
    pad_width = Wh // 2
    image_padding = zero_pad(x, pad_height, pad_width)
    h_flip = np.flip(np.flip(h, 0), 1) #np.flip 是翻转函数,参数0为上下翻转也就是行翻转,而参数1为左右翻转也就是列翻转

    for i in range(Hi):
        for j in range(Wi):
            out[i][j] = np.sum(np.multiply(h_flip, image_padding[i:(i+Hh), j:(j+Wh)]))# 加权求和后写入结果到out对应位置

    return out

data = scio.loadmat(dataFile) #此时读取到的为dict形式
x = data['matrix']#读取其中的矩阵
h = np.array([[-1,-2,-1],
     [0,0,0],
     [1,2,1]]) #Sobel算子

print('conv2d(x,h) :')
print(conv_fast(x,h)) #输出卷积后的矩阵
print(conv_fast(x,h).shape) #输出矩阵大小

然后我继续处理,因为这样得到的矩阵大小还是200 * 200
参数’full’:
拿到完整的卷积结果

参数’same’:
以中间向两边散开,拿到第一个输入数组同样长度的卷积数组
ps:如果输入数组是偶数长度,则最后一个数向左边取

参数’valid’:
拿到卷积序列的中间部分的一个/两个数(若x×y-1为奇数则取1个,偶数则取2个)

继续更改代码,我发现用signal.convolve2d()这个函数可以直接对两个矩阵卷积,继续修改代码

import numpy as np
import scipy.io as scio
from scipy import signal

dataFile = 'K://数据集/train/00001/1/1.mat' #数据位置

data = scio.loadmat(dataFile)
x = data['matrix']
h = np.array([[-1,-2,-1],
     [0,0,0],
     [1,2,1]]) #卷积核

s = signal.convolve2d(x,h, 'valid')

print(s)
print(s.shape)

这样得到的矩阵大小是198 * 198的,那我是不是可以循环一下,那要减少150岂不是要循环75次??

七、最终处理

因为我是要对矩阵下4采样,就是说从200 * 200大小的矩阵得到50 * 50大小的矩阵,所以要对上述的代码进行一定的更改:

import numpy as np
import scipy.io as scio
from scipy import signal

dataFile = 'K://数据集/train/00001/1/1.mat' #数据位置

data = scio.loadmat(dataFile)
x = data['matrix']
h = np.array([[-1,-2,-1],
     [0,0,0],
     [1,2,1]]) #卷积核

for i in range(0,75):
    s = signal.convolve2d(x,h, 'valid')
    x = s

print(s)
print(s.shape)

New_data = 'K://数据集/LR/1.mat'

scio.savemat(New_data,{'s':s})

这样就得到了50 * 50大小的矩阵了,再把它保存一下~~~

在保存那遇到了点问题,因为mat文件存入的是字典,而我们s中存的是数组,刚开始用的是scio.savemat(New_data,{‘s’:data[‘s’]}),一直说KeyError:s,然后发现,直接像上面那样写就可以了!

所以就处理完了,现在就是写个循环对我所有的mat文件下采样就行了~~~

补:
我又发现了一点问题……

这样卷的太狠了,丢失了很多信息,转换出来的图像和之前差距特别大,我觉得,可能要设置卷积步长,卷一次那种,不是卷这么多次,弄出来是个什么东西,哭了……

行,自己写了一个……

import numpy as np
import scipy.io as scio
from scipy import signal

dataFile = 'K://数据集/train/00001/1/1.mat' #数据位置

data = scio.loadmat(dataFile)
x = data['matrix']
h = np.array([[-1,-2,-1],
     [0,0,0],
     [1,2,1]]) #卷积核

def convolution(h, x):
     n,m = x.shape #n为行,m为列
     new = []

     for i in range(1,n+1,4):
         line = []
         for j in range(1,m+1,4):
              a = x[i:i+3,j:j+3]
              a = signal.convolve2d(a,h,'valid')
              line.append(a[0][0])
         new.append(line)
     return np.array(new)

new = convolution(h, x)#卷积过程

print(x.shape)
print(new.shape)

a[0][0]是因为如果用a,那么new的shape输出会是(50,50,1,1),而且就是,每一个数据外面多了两层括号,所以就给删了……

大功告成!

参考链接:
1、https://blog.csdn.net/liulina603/article/details/47727277/
2、https://www.zhihu.com/question/22298352
3、https://www.sohu.com/a/241208957_787107
4、https://www.pianshen.com/article/302985268/
5、https://blog.csdn.net/CSDN_CQD/article/details/105224388
6、https://blog.csdn.net/weixin_41861700/article/details/103649951

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值