高中生能看懂的详细通俗讲解卡尔曼滤波Kalman Filter原理及Python实现教程

接触过传感器数据的同学一定不可避免见到一个名字“卡尔曼滤波”。这是何方神圣?请看后面分晓。很多时候看不懂一个算法是因为里面很多概念上的问题你没了解,就直接看细节了当然看不懂。最关键的事就是你得先了解卡尔曼滤波到底有啥用,它的初衷是什么?接下来我就是想讲讲破解卡尔曼滤波的一些概念上的认知障碍这个事。

破解概念上的认知枷锁:卡尔曼滤波做的事

卡尔曼滤波做的事就是:举个例子,已知上个时刻飞机的位置,知道现在这个时刻收到的雷达测量的飞机的位置。用前面两个数据来估计此时飞机的位置。精简的说就是知道上个时刻状态,又知道测量数据,融合这两个数据来求当前状态。

你一定会问现在知道当前时刻的测量数据那么我认为当前状态就是测量数据不就好了么?换句话说:“你一定会觉得雷达测量到的飞机位置不就是当前飞机的位置嘛?为何要用卡尔曼滤波来估计飞机当前的位置?”。
答:现在这个时刻收到的雷达信号测量的飞机的位置还真不一定是飞机当前的真实位置。首先雷达信号测量有误差。其次你想想我现在收到雷达信号,那是之前发射过去然后返回的信号。这个过程是不是要时间?这段时间飞机说不定以超2倍音速飞行,说不定直接坠机,这些都有可能**。也就是说即使收到测量数据但是还是不确飞机位置在哪**。于是我得需要根据前一个时刻的位置估计出当前时刻的飞机位置 结合 测量数据 综合考虑来 估计当前飞机位置。这就是卡尔曼滤波的作用。

那么你一定会问根据前一个时刻估计的飞机位置怎么就可以估计现在这个时刻的飞机位置了?
答:卡尔曼认为所有的状态变化(位置变化)都是线性的。什么叫做线性?上个时刻位置是0.3,速度是0.2。那么我估计下个时刻的位置就是0.5。这就叫做线性。

接下来你一定会问那并不是所有的状态变化都是线性的怎么办?你像风速变化它就不是线性的
答:恭喜你发明了新的算法。事实上别人已经为这个算法命名了叫做扩展卡尔曼滤波。现在我们要学习的是卡尔曼滤波。你只需要记住卡尔曼滤波就是认为所有变化都是线性的

那么现在我知道了怎么用上个时刻飞机的位置估计当前时刻的飞机位置,也知道了还得借助当前时刻收到的测量数据来综合考虑来估计当前飞机的位置。那么怎么综合考虑呢?这就涉及到一个比例。到底这两个数据占比多少?这就是卡尔曼滤波的核心精髓。卡尔曼滤波算法要动态的调这个比例。(有种中庸之道的调调,既不只信测量数据,也不只信上个时刻的位置所估算的当前时刻位置。)

滤波算法的思路发展?

如果不理解滤波思路那么今天学会了一个卡尔曼滤波明天还有一个通尔曼滤波要你学。如果学会这些滤波算法的思路,把他们联系在一起然后记忆那就简单多了。滤波算法本质上就是利用多个数据来融合估计真实状态。下面举两个从浅到深的例子。

如何结合“飞机的速度和雷达测量的飞机的位置 ”来估计飞机在 t 2 t_2 t2时刻的位置?

下面有个一个飞机只会水平飞行。我们已知上个时刻飞机的位置 x 1 x_1 x1和速度 v 1 v_1 v1.而且雷达可以测量到 t 2 t_2 t2此时飞机的位置 x 2 ∗ x_2^* x2。那么我们估计飞机的位置那就有两种方法:“一是认为飞机是匀速( v 2 = v 1 v_2=v_1 v2=v1)直线运动得到现在飞机位置为 x 1 + v 2 ( t 2 − t 1 ) x_1+v_2(t_2-t_1) x1+v2(t2t1),另一种是认为飞机位置就是测量值 x 2 ∗ x_2^* x2”。如果按第一种那么万一飞机不是匀速走呢?如果按第二种万一雷达很不准呢?我们得采取一种折中的方法。
我们认为飞机在时刻 t 2 t_2 t2的位置为 x 2 r e a l = ( x 1 + v 2 ( t 2 − t 1 ) ) + α [ x 2 ∗ − ( x 1 + v 2 ( t 2 − t 1 ) ) ] x_2^{real}=(x_1+v_2(t_2-t_1))+\alpha [x_2^* - (x_1+v_2(t_2-t_1))] x2real=(x1+v2(t2t1))+α[x2(x1+v2(t2t1))]。这个 α \alpha α需要我们自己设置。如果我们相信雷达不准那就 α \alpha α赋值很低比如为0.1.如果我们相信雷达很准那么就设置 α \alpha α为很接近1的值比如0.9。你会发现 α \alpha α越接近0,那么所估计的位置越是接近认为飞机匀速走的那个思路。越接近1那么所估计的位置越接近雷达测量值(等于1就是认为飞机在时刻 t 2 t_2 t2的位置就是雷达测量值)。
在这里插入图片描述
但是飞机的速度怎么估计啊?因为飞机不一定是匀速走。我们得根据
现在我想估计飞机的速度。
速度估计的方式有两种:

  1. 假设飞机是匀速运动。也就是说 t 1 t_1 t1 t 2 t_2 t2这段时间内飞机速度等于在 t 1 t_1 t1时刻估计出的飞机速度 v 1 v_1 v1。即 v 2 = v 1 v_2=v1 v2=v1
  2. 由于雷达也收到了一个测量数据,它测量到雷达距离飞机位置是 x 2 ∗ x_2^* x2。也就是说在雷达看来从 t 1 t_1 t1 t 2 t_2 t2这段时间内飞机走过了 x 2 ∗ − x 1 x_2^*-x_1 x2x1这么远的距离。所以根据雷达的判断,我们可以估计出飞机的一个速度 v 2 ∗ = x 2 m e a s u r e − x 1 r e a l t 2 − t 1 v_2^*=\frac {x_2^{measure}-x_1^{real}}{t_2-t_1} v2=t2t1x2measurex1real
    这两种速度很可能不同。这有两个原因:“一是飞机并不是匀速运动,二是雷达根本就测量的距离不准”。到底是哪个对呢?
    真实速度需要综合考虑这两个数值,根据上一个例子总结的滤波器模式第N次算出的估计值=上次的估计值+ 因子a ×(测量值-上次估计值)。我们知道真实的速度肯定可以这么表达 v 2 r e a l = v 1 + β × ( v 2 ∗ − v 1 r e a l ) v_2^{real}=v_1+\beta \times (v_2^*-v_1^{real}) v2real=v1+β×(v2v1real)。至于这个 β \beta β到底取多少这是我们自己赋值。比如我们觉得测量的值是更准确的,那 β \beta β可以设置大一点比如0.9。如果我们觉得雷达不准那就 β \beta β设置小一点比如0.1。
    所以我们得到速度的估计公式:
    v 2 r e a l = v 1 r e a l + β × ( v 2 ∗ − v 1 r e a l ) v_2^{real}=v_1^{real}+\beta \times (v_2^*-v_1^{real}) v2real=v1real+β×(v2v1real),其中 v 2 ∗ = x 2 m e a s u r e − x 1 r e a l t 2 − t 1 v_2^*=\frac {x_2^{measure}-x_1^{real}}{t_2-t_1} v2=t2t1x2measurex1real
    然后我们又可以根据这个求得的速度来更精确的估计飞机的位置
    x 2 r e a l = ( x 1 r e a l + v 2 r e a l ( t 2 − t 1 ) ) + α [ x 2 ∗ − ( x 1 r e a l + v 2 r e a l ( t 2 − t 1 ) ) ] x_2^{real}=(x_1^{real} +v_2^{real}(t_2-t_1))+\alpha [x_2^* - (x_1^{real}+v_2^{real}(t_2-t_1))] x2real=(x1real+v2real(t2t1))+α[x2(x1real+v2real(t2t1))]

如何结合“飞机的速度,加速度,雷达测量的飞机的位置” 来估计飞机的位置?

在前面我们一直做的假设是飞机是匀速走的。但是飞机很可能会发生加速或者减速。这就不得不考虑加速度的问题了。
在高中我们学过位移与速度和加速度之间的关系是: x 2 = x 1 + v 1 ( t 2 − t 1 ) + 1 2 a 2 ( t 2 − t 1 ) 2 x_2=x_1+v_1(t_2-t_1)+\frac 1 2 a_2(t_2-t_1)^2 x2=x1+v1(t2t1)+21a2(t2t1)2。其中 a 2 a_2 a2是从 t 1 t_1 t1 t 2 t_2 t2这段时间的加速度。
所以飞机的位置可以融合速度、加速度这样来估计 x 2 r e a l = ( x 1 r e a l + v 2 r e a l ( t 2 − t 1 ) + 1 2 a 2 ( t 2 − t 1 ) 2 ) ) + α [ x 2 ∗ − ( x 1 r e a l + v 2 r e a l ( t 2 − t 1 ) + 1 2 a 2 ( t 2 − t 1 ) 2 ) ] x_2^{real}=(x_1^{real}+v_2^{real}(t_2-t_1)+\frac 1 2 a_2 (t_2-t_1)^2))+\alpha [x_2^* - (x_1^{real}+v_2^{real}(t_2-t_1)+\frac 1 2 a_2 (t_2-t_1)^2)] x2real=(x1real+v2real(t2t1)+21a2(t2t1)2))+α[x2(x1real+v2real(t2t1)+21a2(t2t1)2)]
可以看到和前面那个例子的位置估计公式:
x 2 r e a l = ( x 1 r e a l + v 2 r e a l ( t 2 − t 1 ) ) + α [ x 2 ∗ − ( x 1 + v 2 r e a l ( t 2 − t 1 ) ) ] x_2^{real}=(x_1^{real}+v_2^{real}(t_2-t_1))+\alpha [x_2^* - (x_1+v_2^{real}(t_2-t_1))] x2real=(x1real+v2real(t2t1))+α[x2(x1+v2real(t2t1))]相比,只是将原来的根据速度估计位移变成了根据速度和加速度来估计位移。
在前面提到了我们的速度可以根据测量数进行动态更新
v 2 r e a l = v 1 r e a l + β × ( v 2 ∗ − v 1 r e a l ) v_2^{real}=v_1^{real}+\beta \times (v_2^*-v_1^{real}) v2real=v1real+β×(v2v1real),其中 v 2 ∗ = x 2 m e a s u r e − x 1 r e a l t 2 − t 1 v_2^*=\frac {x_2^{measure}-x_1^{real}}{t_2-t_1} v2=t2t1x2measurex1real
当然我们的加速度也是可以根据测量数据进行动态更新的
a 2 r e a l = a 1 r e a l + γ × ( a 2 ∗ − a 1 r e a l ) a_2^{real}=a_1^{real}+\gamma \times(a_2^*-a_1^{real}) a2real=a1real+γ×(a2a1real)。其中 a 2 ∗ = v 2 r e a l − v 1 r e a l t 2 − t 1 a_2^*=\frac{v_2^{real}-v_1^{real}}{t_2-t_1} a2=t2t1v2realv1real,这个是根据加速度的定义所得来的,加速度=速度变化量除以时间间隔。

可以看到滤波思路是一环扣一环,它要平衡每个环节中的 根据之前状态所估计出当前状态值测量值之间的在最终结果中的占比。

而那些滤波算法要做的事就是设计合理的占比到底取多少比较合适。而且是需要根据不同情况动态的设置占比。前面提到的例子中占比变量有三个 α , β , γ \alpha,\beta,\gamma α,β,γ,你学习滤波算法时只需要关注这几个占比值是怎么计算的就可以了。

像卡尔曼滤波,拓展的卡尔曼滤波,Particle Filter,贝叶斯滤波等等都是前面提到滤波思路这种形式。

卡尔曼滤波怎么进行滤波的?

我们先把前面总结的滤波算法规律复制过来看看:

  1. 估计当前时刻位置
    x 2 r e a l = ( x 1 r e a l + v 2 r e a l ( t 2 − t 1 ) + 1 2 a 2 ( t 2 − t 1 ) 2 ) ) + α [ x 2 ∗ − ( x 1 r e a l + v 2 r e a l ( t 2 − t 1 ) + 1 2 a 2 ( t 2 − t 1 ) 2 ) ] x_2^{real}=(x_1^{real}+v_2^{real}(t_2-t_1)+\frac 1 2 a_2 (t_2-t_1)^2))+\alpha [x_2^* - (x_1^{real}+v_2^{real}(t_2-t_1)+\frac 1 2 a_2 (t_2-t_1)^2)] x2real=(x1real+v2real(t2t1)+21a2(t2t1)2))+α[x2(x1real+v2real(t2t1)+21a2(t2t1)2)]
  2. 估计当前时刻速度
    v 2 r e a l = v 1 r e a l + β × ( v 2 ∗ − v 1 r e a l ) v_2^{real}=v_1^{real}+\beta \times (v_2^*-v_1^{real}) v2real=v1real+β×(v2v1real),其中 v 2 ∗ = x 2 m e a s u r e − x 1 r e a l t 2 − t 1 v_2^*=\frac {x_2^{measure}-x_1^{real}}{t_2-t_1} v2=t2t1x2measurex1real
  3. 估计当前时刻加速度
    a 2 r e a l = a 1 r e a l + γ × ( a 2 ∗ − a 1 r e a l ) a_2^{real}=a_1^{real}+\gamma \times(a_2^*-a_1^{real}) a2real=a1real+γ×(a2a1real)。其中 a 2 ∗ = v 2 r e a l − v 1 r e a l t 2 − t 1 a_2^*=\frac{v_2^{real}-v_1^{real}}{t_2-t_1} a2=t2t1v2realv1real

前面我们提到了那些种类繁多的滤波算法,无非就是提出了各种确定 α , β , γ \alpha,\beta,\gamma α,β,γ具体取值的计算方法而已
我们看看卡尔曼滤波是怎么确定这三个值的。

  • α \alpha α这个是用来调节 根据上个位置估计出的当前位置值测量值 在最终结果中的占比用的。这个在卡尔曼滤波中叫做卡尔曼增益。当然既然叫卡尔曼增益了肯定变量名就不叫做 α \alpha α了而是叫做 K n K_{n} Kn
  • β \beta β是用来调节根据上个时刻速度估计出的当前时刻速度值根据测量值算出的速度 在最终结果中的这两个数占比用的。在卡尔曼滤波中它认为物体就是匀速运动的。所以当前时刻速度和上个时刻速度一样,即 β = 0 \beta=0 β=0
  • 上面那句话提到了物体是匀速运动的所以没有加速度。

于是卡尔曼滤波可以这么写:

  1. 估计当前时刻位置
    x 2 r e a l = ( x 1 r e a l + v 2 r e a l ( t 2 − t 1 ) ) + K n × [ x 2 ∗ − ( x 1 r e a l + v 2 r e a l ( t 2 − t 1 ) ] x_2^{real}=(x_1^{real}+v_2^{real}(t_2-t_1))+K_n \times [x_2^* - (x_1^{real}+v_2^{real}(t_2-t_1)] x2real=(x1real+v2real(t2t1))+Kn×[x2(x1real+v2real(t2t1)]
  2. 估计当前时刻速度
    v 2 r e a l = v 1 r e a l v_2^{real}=v_1^{real} v2real=v1real

那么 K n K_n Kn怎么计算呢?
K n = 根 据 上 个 状 态 算 出 当 前 状 态 这 种 方 法 的 方 差 p n − 1 根 据 上 个 状 态 算 出 当 前 状 态 这 种 方 法 的 方 差 p n − 1 + 测 量 仪 器 的 方 差 K_{n}= \frac{根据上个状态算出当前状态这种方法的方差p_{n-1}}{根据上个状态算出当前状态这种方法的方差p_{n-1}+测量仪器的方差} Kn=pn1+pn1

橘黄色虚线是根据市上个状态计算出当前状态的估计值,绿色虚线是测量值,紫色虚线是最终结果。而 K n K_n Kn这个数字就是调节紫色虚线到底是靠近另外两条线中的哪个
现在我们得到了新的位置估计值,那么根据这个来估计下一个位置它的方差 p n − 1 p_{n-1} pn1是多少呢?由于根据上个状态算出当前状态这个数字在最终结果的占比只占了 1 − K n 1-K_n 1Kn这么多。所以方差 p n = ( 1 − k n ) p n − 1 p_{n}=(1-k_n)p_{n-1} pn=(1kn)pn1

由上面这段话可以看出,卡尔曼滤波最关键的是需要求出两种方差。一是纯粹依赖估计的这种方法的方差。二是测量仪器的方差。只要知道了这两个值那就可以知道估计值和测量值在最终结果中的占比。算方差的方法在不同应用场景是不同的需要以实际情况而定。

注意:根据上个状态估计当前时刻的位置方法不是只有根据速度和加速度来估计这一种方法。还有其他很多种。比如我可以根据飞机发动机此时的推动力和这段时间内燃烧了的汽油来估计飞机飞行了的距离(能量守恒定律,推动力×距离=做功)。

在这里插入图片描述

Python编程实践卡尔曼滤波

"""
@司南牧 
"""
import numpy as np

# 模拟数据
t = np.linspace(1,100,100)
a = 0.5
position = (a * t**2)/2

position_noise = position+np.random.normal(0,120,size=(t.shape[0]))
import matplotlib.pyplot as plt
plt.plot(t,position,label='truth position')
plt.plot(t,position_noise,label='only use measured position')


# 初试的估计导弹的位置就直接用GPS测量的位置
predicts = [position_noise[0]]
position_predict = predicts[0]

predict_var = 0
odo_var = 120**2 #这是我们自己设定的位置测量仪器的方差,越大则测量值占比越低
v_std = 50 # 测量仪器的方差
for i in range(1,t.shape[0]):
  
    dv =  (position[i]-position[i-1]) + np.random.normal(0,50) # 模拟从IMU读取出的速度
    position_predict = position_predict + dv # 利用上个时刻的位置和速度预测当前位置
    predict_var += v_std**2 # 更新预测数据的方差
    # 下面是Kalman滤波
    position_predict = position_predict*odo_var/(predict_var + odo_var)+position_noise[i]*predict_var/(predict_var + odo_var)
    predict_var = (predict_var * odo_var)/(predict_var + odo_var)**2
    predicts.append(position_predict)

    
plt.plot(t,predicts,label='kalman filtered position')

plt.legend()
plt.show()

在这里插入图片描述

数学小知识:

数学期望值与平均值的区别?
大家平常把这两个等价为一个好像并没什么很大影响。事实上他们两个确实差不多。但是又有微小的差异。
假设有个2个硬币:1元,5元。你说它平均值是3元这个没错。但是你不能说它期望值是3元。因为这个硬币它整体我们已经可以看完了。而且期望值是针对那些样本整体我们没法看完的情况,我们对他们整体的平均值的一个估计。平均值一般是用希腊字母 μ \mu μ(读音:miu)表示,期望值一般用 E E E表示。这个符号很关键。因为作者写公式的时候就隐含了这些信息。他默认你知道这个概念认知

方差与标准差?
方差就是一个数。这个数可以衡量样本集中各个样本值与平均值之间的波动大小。(还记得平均值用什么符号表示么?平均值用 μ \mu μ)。怎么衡量与平均值波动大小?很简单我减去平均值然后平方不就好了么。然后由于是要衡量整个样本集中的样本,那就得把那个平方求和然后除以样本个数(关于到底除N还是N-1,可以看看这篇文章Why divide the sample variance by N-1?)。我们熟悉的方差公式出来啦: σ 2 = 1 N ∑ n = 1 N ( x n − μ ) 2 \sigma ^{2}= \frac{1}{N} \sum _{n=1}^{N} \left( x_{n}- \mu \right) ^{2} σ2=N1n=1N(xnμ)2。注意: σ 2 \sigma ^{2} σ2(含义:sigma的平方)这个表示方差。N表示样本的个数。 μ \mu μ是样本集的平均值。 x n x_n xn表示第n个样本。
标准差也是一个数。它就是方差开根号。和方差没啥区别。还记得方差是什么吗?它是sigma的平方。标准差是方差开根号,也就是说标准差就是sigma。即用符号表示就是 σ \sigma σ,这就是标准差。
标准差有什么用
衡量样本值与平均值之间的波动大小这个你肯定高中就知道了。我想说的是另外一个作用:根据样本估计真实值的范围。
假设我们抽样了溶液x的样本数据。测量他们的电压。然后他们的分布如下所示。根据这些我们可以得出一个结论:溶液x电压值在 [ 0 , 1 σ ] [0,1σ] [0,1σ]之间的概率是34.1%。溶液x的电压在 [ − 1 σ , 1 σ ] [-1σ,1σ] [1σ,1σ]之间的概率是68.2%。也就是说溶液x的电压大概率在 [ − 1 σ , 1 σ ] [-1σ,1σ] [1σ,1σ]范围内?而 σ σ σ就是标准差。是不是很有用?我们可以根据所收集的很多测量值,算他们的均值和标准差来估计真实值的范围。这个原理就是滤波算法的很常用的原理。
在这里插入图片描述

正态分布不清楚?
下面这个图就是正态分布。横坐标是在本例中是飞机的速度v,纵坐标是当前速度是v的概率。其实这些你编程就调用一个服从正态分布的随机函数就是了。正态分布函数用公式表示就是 f ( v ) = 1 2 π σ 2 e − ( v − μ ) 2 2 σ 2 f( v) = \frac{1}{\sqrt[]{2 \pi \sigma ^{2}}}e^{\frac{- \left( v- \mu \right) ^{2}}{2 \sigma ^{2}}} f(v)=2πσ2 1e2σ2(vμ)2 f ( v ) f(v) f(v)这个函数,表示的是当前速度为 v v v的概率是 f ( v ) f(v) f(v)。还记得 μ , σ \mu , \sigma μ,σ是什么吗? u u u是平均值, σ \sigma σ是标准差。 μ , σ \mu , \sigma μ,σ这两个是常数,你编程的时候需要告诉程序,告诉它生成的随机数平均值是多少,标准差是多少。一般生成正态分布随机数代码是这么写的 v = normalrand(u,s)
在这里插入图片描述

参考文献:
[1] http://web.mit.edu/kirtley/kirtley/binlustuff/literature/control/Kalman%20filter.pdf
[2] https://www.bzarg.com/p/how-a-kalman-filter-works-in-pictures/
[3] https://en.wikipedia.org/wiki/Kalman_filter
[4] http://www.cl.cam.ac.uk/~rmf25/papers/Understanding%20the%20Basis%20of%20the%20Kalman%20Filter.pdf
[5] https://www.kalmanfilter.net/alphabeta.html

  • 154
    点赞
  • 657
    收藏
    觉得还不错? 一键收藏
  • 29
    评论
卡尔曼滤波是一种用来估计系统状态的递归滤波算法,适用于线性系统且满足高斯分布的噪声。该滤波器是由R. E. Kalman提出的。 卡尔曼滤波原理是基于两个假设:系统动态方程能由线性方程描述,测量方程能由线性方程描述。在每个时间步,卡尔曼滤波器通过两个步骤进行估计和更新:预测步骤和校正步骤。预测步骤是根据系统动态方程和上一个时间步的估计状态预测当前状态的均值和方差。校正步骤是根据测量方程和当前观测得到的测量值以及预测的状态,利用贝叶斯定理更新状态的均值和方差,得到最终的估计值。 推导卡尔曼滤波算法的公式如下: 预测步骤: 预测状态: $ x^- = A \cdot x + B \cdot u $ 预测状态协方差矩阵: $ P^- = A \cdot P \cdot A^T + Q $ 校正步骤: 卡尔曼增益: $ K = P^- \cdot H^T \cdot (H \cdot P^- \cdot H^T + R)^{-1} $ 修正后的状态: $ x = x^- + K \cdot (z - H \cdot x^-) $ 修正后的状态协方差矩阵: $ P = (I - K \cdot H) \cdot P^- $ 其中,x是系统状态向量,A是状态转移矩阵,B是输入矩阵,u是输入向量,P是后验状态的误差协方差矩阵,Q是预测误差协方差矩阵,H是测量矩阵,R是测量误差的协方差矩阵,z是观测向量。 通过上述公式的迭代,卡尔曼滤波器可以递归地估计系统的状态,并通过校正步骤利用最新的观测值来更新估计值。这种算法在估计方差较大的实时系统中具有优势,可以去除噪声和不确定性,提高系统的估计精度。
评论 29
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值