十大滤波(C++版)

在翻阅了网上多个版本的滤波算法,发现很多仍停留在多年以前,很多版本的更替没有完成。

自己和小伙伴研究了一下,研究成果如下,因为都是比较浅显的研究,如果有不符合常理的地方,请大家指出,一起进步。

一、限幅滤波

#include<iostream>
#include<cmath>
#include<vector>
using namespace std;
//限幅滤波:设置一个幅值,当相邻的两个数据之差的绝对值大于该幅值,则认为新数据无效,用旧数据(有效数据)覆盖掉新数据(无效数据),循环这个过程,直到数组结束。
//old_value用来存储原数据,rst存储滤波结果,limit是设定的幅值
void limite_filter(vector<int> &old_value, vector<int> &rst, double limit){
    rst.push_back(old_value[0]);                                                //给rst一个初始参考值
    for(int i = 1; i < old_value.size(); i++){                                    //利用循环将数组遍历
        if((abs(old_value[i] - rst[i-1])) >= limit)                                //判断相邻两数据差值是否超过幅值
        {
            rst.push_back(rst[i - 1]);                                            //超过则用老数据覆盖新数据
        }
        else
        {
            rst.push_back(old_value[i]);                                        //未超过则将新数据存入
        }
    }                                                                            
}
//滤波过后原数据不变,滤波数据存储在rst容器中
// 测试限幅滤波功能
void test_limite_filter(){
    vector<int> data1 = {55,54,53,52,51,50,55,100,50,51};
    vector<int> data2;
    double limit = 5;

    limite_filter(data1, data2, limit);

    cout << "原始数据: ";
    for(auto d : data1){
        cout << d << " ";
    }
    cout << endl;

    cout << "滤波后数据: ";
    for(auto r : data2){
        cout << r << " ";
    }
    cout << endl;
}

int main(){
    test_limite_filter();
    return 0;
}

二、中位值滤波

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

//中位值滤波
//从一个数周围取n个数据,将这n个数据排序后取得中位值,将该中位值作为这个点的滤波值
void mid_value(int N, vector<double> &data, vector<double> &rst){
    int n = data.size(), count = 0;
    while(count < n - N + 1){
        vector<double> temp(data.begin() + count, data.begin() + count + N);
        sort(temp.begin(), temp.end()); // 使用标准库函数进行排序

        if(N % 2 == 0)
            rst.push_back((temp[N / 2] + temp[(N - 1) / 2]) / 2);
        else
            rst.push_back(temp[(N - 1) / 2]);

        count++;
    }
}

// 测试中位值滤波功能
void test_mid_value(){
    vector<double> data = {3, 5, 1, 8, 2, 7, 4, 6};
    vector<double> rst;
    int N = 3;

    mid_value(N, data, rst);

    cout << "原始数据: ";
    for(auto d : data){
        cout << d << " ";
    }
    cout << endl;

    cout << "滤波后数据: ";
    for(auto r : rst){
        cout << r << " ";
    }
    cout << endl;
}

int main(){
    test_mid_value();
    return 0;
}

三、均值滤波

#include<iostream>
#include<vector>
using namespace std;
//均值滤波与滑动滤波区别:最主要的区别:取值位置的不同,均值滤波是取N个周期的相同位置的数据进行计算,得出一个均值认定这个值为对应值。
//而滑动平均滤波是采连续的N个数,在这连续的N个数中,每次取n个数据进行处理
//n为每次处理的数据量,data中存储了所有的传入数据,rst中存储平均值
void avg(int n, vector<double> &data, vector<double> &rst){
    int size = data.size();

    for(int i = 0; i < size - n + 1; i++){
        double sum = 0;                                     // 每次计算平均值前需要将 sum 置零
        for(int j = i; j < n + i; j++){
            sum += data[j];
        }
        rst.push_back(sum / n);                             // 将平均值添加到结果数组中
    }
}

// 测试平均值滤波算法功能
void test_avg(){
    vector<double> data = {3, 5, 1, 8, 2, 7, 4, 6};
    vector<double> rst;
    int n = 3;

    avg(n, data, rst);

    cout << "原始数据: ";
    for(auto d : data){
        cout << d << " ";
    }
    cout << endl;

    cout << "平均值: ";
    for(auto r : rst){
        cout << r << " ";
    }
    cout << endl;
}

int main(){
    test_avg();
    return 0;
}

四、滑动平均滤波

#include<iostream>
#include<vector>
using namespace std;

//滑动平均滤波需要设置一个窗口值来确定每次进行取均值计算的数据个数,然后通过主函数中的循环调用,每次输入不同的n个数据来进行取均值处理
//N为窗口值,data为传入数据的数组,rst为存储结果的数组
void mv_avg_filter(int N, vector<double> &data, vector<double> &rst){
    int count = 0, size = data.size();                                //设置计数器,获得传入数组的大小

    while(count < size - N + 1){                                      //设置循环次数
        double sum = 0;                                               // 每次计算均值前需要将 sum 置零
        for(int i = count; i < N + count; i++){
            sum += data[i];                                           //求和
        }
        double avg = sum / N;                                         // 求均值
        rst.push_back(avg);                                           // 将求得的均值添加到 rst 数组中
        count++;
    }
}

// 测试滑动平均滤波功能
void test_mv_avg_filter(){
    vector<double> data = {3, 5, 1, 8, 2, 7, 4, 6};
    vector<double> rst;
    int N = 3;

    mv_avg_filter(N, data, rst);

    cout << "原始数据: ";
    for(auto d : data){
        cout << d << " ";
    }
    cout << endl;

    cout << "滤波后数据: ";
    for(auto r : rst){
        cout << r << " ";
    }
    cout << endl;
}

int main(){
    test_mv_avg_filter();
    return 0;
}

五、防脉冲干扰平均滤波

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

//输入所有数据,每次取一定数量的数据,排序后去除最大值与最小值,将剩余数据进行取均值处理,最后返回均值
//传入数据data,设置窗口值N,存储结果rst
//sum数据和,temp做排序中间值,count计数器,size传入数组的大小,avg均值
void im_int_filter(vector<double> &data, double N, vector<double> &rst){
    int sum = 0, temp = 0, count = 0, size = data.size();
    double avg;
    
    while(count < size - N + 1){                                                    //设置循环次数
        vector<double> temp_data(data.begin() + count, data.begin() + count + N);    //使用data数组的指针来初始化temp_data
        sort(temp_data.begin(), temp_data.end());                                    //使用标准库函数进行排序

        for(int i = 1; i < N - 1; i++){                                                //去头去尾(去掉最大值与最小值),然后求和
            sum += temp_data[i];
        }
        avg = sum / (N - 2);                                                        //取平均值
        rst.push_back(avg);                                                            //将均值存入rst数组中,rst.push_back(avg)将avg插入到数组的尾端
        sum = 0;                                                                    // 每次计算均值后需要将 sum 置零
        count++;
    }
}

// 测试滤波功能
void test_im_int_filter(){
    vector<double> data = {3, 5, 1, 8, 2, 7, 4, 6};
    vector<double> rst;
    double N = 5;

    im_int_filter(data, N, rst);

    cout << "原始数据: ";
    for(auto d : data){
        cout << d << " ";
    }
    cout << endl;

    cout << "滤波后数据: ";
    for(auto r : rst){
        cout << r << " ";
    }
    cout << endl;
}

int main(){
    test_im_int_filter();
    return 0;
}

六、限幅均值滤波

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

// 限幅平均滤波函数
//data为传入数组,N为窗口值,A为限幅阈值,rst为存储结果的数组
void limit_average_filter(vector<double> &data, int N, double A, vector<double> &rst)
{
    double sum = 0;                                                    //记录滤波后的数据总和来求出最后需要的均值
    int count = 0;                                                    //计数器
    double result = 0.0;                                            //最终计算结果
    int size = data.size();                                            //得到传入数组的大小
    vector<double> arr;                                                //用来存储限幅后的数据
    arr.push_back(data[0]);                                            //赋予初值
    for(int i = count; i < count + N; i++)                            //利用循环进行限幅滤波
    {
        if( abs(arr[i] - data[i+1]) < A)                            // 若当前数据与上次滤波结果之差小于阈值 A,则将当前数据存入数组
        {
            arr.push_back(data[i+1]);
        }else{                                                        //否则将上次滤波结果传入数组
            arr.push_back(arr[i]);
        }
    }
    while(count < size - N + 1){                                    //设置循环次数,开始滑动均值滤波
        for(int k = 0;k < N; k++){                                    //每次取N个值进行求均值处理
            sum += arr[k];
        }
        result = sum / N;
        rst.push_back(result);                                        //将计算结果存储到数组中
        count++;                                                    
        sum = 0;                                                    //每次循环都将sum值清零
    }
    
}

int main()
{
    // 测试数据,M为数据量
    int M = 10;
    double data[M] = {1.0, 2.0, 1.0, 0.5, 0.5, 1.0, 2.0, 0.3, 0.2, 1.2};
    // 滤波窗口大小
    int N = 5;
    //计算结果个数
    int J = M - N + 1;
    // 限制阈值
    double A = 1.0;
    // 调用限幅平均滤波函数
    vector<double> result;
    for(int i = 0; i < J; i++){
        vector<double> temp(N);
        int k = i;
        for(int j = 0; j < N; j++){
            temp[j] = data[k];
            k++;
        }
        limit_average_filter(temp, N, A, result);
    }
    // 输出滤波结果
    for(int c = 0; c < result.size(); c++){
        cout << "滤波结果为:" << result[c] << endl;
    }
    return 0;
}

七、加权平均滤波

#include<iostream>
#include<vector>
using namespace std;

//设定一个窗口值N.传入数据数组data与权重数组weight,设置结果数组rst,最后的数据结果存储到rst中
void wei_avg_fil(int N,vector<double> &data,vector<double> &weight,vector<double> &rst){
    double sum = 0;                                    //数据总和
    double sum_wei = 0,avg = 0;                        //权重总和,平均值
    int count = 0,size = data.size();                //计数器,传入数组大小
    while(count < size - N +1){                        //设定循环条件
        for(int i = count; i < N+count; i ++){        //求数据*权重的和与权重的和
            sum += data[i] * weight[i];                
//            cout << sum <<endl;
            sum_wei += weight[i];                    
        }
        avg = sum / sum_wei;                        //得到均值数据
        rst.push_back(avg);                            //将均值数据传入rst数组的尾端
        sum = 0;                                    //结果存入后将sum值清零
        sum_wei = 0;
        count++;                                    //计数器自加
    }
}

int main(){
    vector<double> data = {1.0, 2.0, 3.0, 4.0, 5.0};
    vector<double> weight = {0.5,0.4,0.3,0.2,0.1};
    vector<double> rst;

    wei_avg_fil(4, data, weight, rst);

    for(int i = 0; i < rst.size(); i++){
        cout << "经由滤波算法过滤后的结果为: " << rst[i] << endl;
    }


    return 0;
}

八、一阶低通滤波 

#include<iostream>
#include<vector>
#include<cmath> // pi的值
using namespace std;

#define pai M_PI

/*
一阶低通滤波:利用公式得出滤波系数a(a的计算方法如下:a = Ts/(Ts+RC)=Ts/(Ts+1/(2πfc))=2πfcTs/(2πfcTs+1)
a的范围为[0,1]),然后利用两个数据(一般一个数据是上次测量或计算得出数据,用old_value来表示,一个为本次试验得到的数据,
用new_value)来进行滤波后数值的计算,然后将数值存入old_value中,计算方法如下:old_value=a * old_value+(1-a)new_value或old_value=anew_value+(1-a)*old_value,
使用哪种算法需要根据a的具体值来进行判断,一般认为,old_value数据更为准确,所以该数据占比会大一些,因此,a与1-a中,占比大的一方来处理old_value。
*/
// 一阶低通滤波函数,alpha为一阶低通滤波系数,Fc为截止频率,Ts为采样周期
double GetAlpha(double fc, double ts){
    double alpha = 2*pai*fc*ts/(2*pai*fc*ts+1);                                        //利用公式计算出滤波系数,也可以直接设置滤波系数
    return alpha;
}

// Function to perform low pass filtering
void low_pass_filtering(double alpha, vector<double> &old_value,vector<double> &rst){
    int size = old_value.size();
    rst.push_back(old_value[0]);
    for(int i = 0; i < size - 1; i++){
        if(alpha > 0.5){
            rst.push_back(alpha * old_value[i] + (1-alpha) * old_value[i+1]);        //一般将旧数据所占比重设置的较大,故公式会根据滤波系数的大小而产生变化
        }else{
            rst.push_back(alpha * old_value[i+1] + (1-alpha) * old_value[i]);
        }
    }
}


void run_test_cases(){
    vector<double> test_data1 = {1, 2, 3, 4, 5};
    vector<double> rst;
    double alpha1 = GetAlpha(5, 0.2);
    low_pass_filtering(alpha1, test_data1,rst);

    cout << "第一个测试结果:" << endl;
    for(int i = 0; i < rst.size(); i++){
        cout << rst[i] << " ";
    }
    cout << endl;

    vector<double> test_data2 = {5, 4, 3, 2, 1};
    vector<double> rst1;
    double alpha2 = GetAlpha(10, 0.1);
    low_pass_filtering(alpha2, test_data2,rst1);

    cout << "第二个测试结果:" << endl;
    for(int i = 0; i < rst1.size(); i++){
        cout << rst1[i] << " ";
    }
    cout << endl;
}

int main(){
    run_test_cases();
    return 0;
}

九、消抖滤波

#include<iostream>
#include<vector>
using namespace std;

//消抖滤波:设置一个阈值N,将传入数据与存储数据进行对比,若传入数据与存储数据不一致,则计数器+1,否则将传入数据返回。
//当传入数据与存储数据不一致,且计数器计数大于阈值N,则将传入数据返回,将其作为新的存储数据。
//N为设置的消抖参数,data为传入的数据,rst存储结果
void De_chat_filter(int N, vector<double> &data, vector<double> &rst) {
    int count = 0,j = 0;                                //count定义计数器,j为rst的下标
    rst.push_back(data[0]);                                //定义初始值(参考值)
    for (int i = 1; i < data.size(); i++) {                //利用循环进行消抖处理
        if (data[i] != rst[j]) {                        //当传入数据与存入数据不匹配时,计数器自增,然后判断计数器是否大于设置的参数,大于参数,则将新数据传入结果数组,并将计数器置零。
            count++;                                    //计数器加一
            if (count >= N) {
                j++;
                rst.push_back(data[i]);
                count = 0;
            }
        }
        else {                                            //当传入数据与存入数据一致时,将传入数据存入结果数组,并将计数器置零
            j++;
            rst.push_back(data[i]);
            count = 0;
        }
    }
}

// 滤波函数检验
void test_De_chat_filter() {
    vector<double> data = { 2.0, 3.0, 2.0, 2.0, 3.0, 3.0, 2.0, 3.0, 2.0, 2.0 };
    vector<double> rst; // 初始化存储数据
    int N = 2; // 阈值设为2

    De_chat_filter(N, data, rst);

    cout << "原始数据:" << endl;
    for (int i = 0; i < data.size(); i++) {
        cout << data[i] << " ";
    }
    cout << endl;

    cout << "滤波后数据:" << endl;
    for (int i = 0; i < rst.size(); i++) {
        if (rst[i] != 0) {
            cout << rst[i] << " ";
        }
    }
    cout << endl;
}

int main() {
    test_De_chat_filter();
    return 0;
}

十、限幅消抖滤波

#include<iostream>
#include<vector>
#include<cmath>
using namespace std;

// 定义限幅消抖滤波函数
//N为幅值,A为消抖参数,data为原数据,rst为结果数据
void cli_den_filter(double N, double A, vector<double> &data, vector<double> &rst){
    int i = 0, j = 0, size = data.size(), count = 0;                        //i,j为循环使用参数,size为data的数据大小,count为消抖计数器
    vector<double> arr(size);                                                //定义数组来存储限幅后的数据
    arr[0] = data[0];                                                        //定义初始值
    for(i = 1; i < size; i++)                                                //利用循环得到限幅后的数据
    {
        if(abs(data[i] - arr[i - 1]) >= N){                                    // 判断信号变化是否超过阈值N,进行限幅处理
            arr[i] = arr[i-1];
        }else{
            arr[i] = data[i];
        }
    }
//    cout << endl;
    for(i = 0; i < size; i++){                                                //进行消抖滤波
        if(arr[i] != arr[i-1]){                                                // 判断是否连续A次相同,输出信号
            count ++;
            if(count >= A){                                                    //当计数器数值大于设置的参数时,将数据存入,并将计数器置零
                rst.push_back(arr[i]);
                count = 0;
            }       
        }else{                                                                //当新数据与老数据相等时,存入新数据,计数器置零
            rst.push_back(arr[i]);
            count = 0;
        }
    }
}

// 测试滤波功能
void test_cli_den_filter(){
    vector<double> data = {2.0, 7.0, 1.0, 1.0, 1.0, 1.0, 2.0};
    vector<double> rst;
    double N = 2;
    double A = 3;

    cli_den_filter(N, A, data, rst);

    cout << "输入数据: ";
    for(auto d : data){
        cout << d << " ";
    }
    cout << endl;

    cout << "输出数据: ";
    for(auto r : rst){
        cout << r << " ";
    }
    cout << endl;

}

int main()
{
    test_cli_den_filter();
    return 0;

                             

滤波测试用例如下:

第一个限幅滤波算法

第二个中位值滤波算法

第三个均值滤波算法

第四个滑动平均滤波算法

第五个防脉冲干扰平均滤波

第六个限幅均值滤波算法

第七个加权平均滤波算法

第八个一阶低通滤波算法

第九个消抖滤波算法

第十个限幅消抖滤波算法

欢迎大家多多交流!

                                     
        

  • 60
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
1、限幅滤波法(又称程序判断滤波法) A、方法: 根据经验判断,确定两次采样允许的最大偏差值(设为A) 每次检测到新值时判断: 如果本次值与上次值之差A,则本次值无效,放弃本次值,用上次值代替本次值 B、优点: 能有效克服因偶然因素引起的脉冲干扰 C、缺点 无法抑制那种周期性的干扰 平滑度差 2、中位值滤波法 A、方法: 连续采样N次(N取奇数) 把N次采样值按大小排列 取中间值为本次有效值 B、优点: 能有效克服因偶然因素引起的波动干扰 对温度、液位的变化缓慢的被测参数有良好的滤波效果 C、缺点: 对流量、速度等快速变化的参数不宜 3、算术平均滤波法 A、方法: 连续取N个采样值进行算术平均运算 N值较大时:信号平滑度较高,但灵敏度较低 N值较小时:信号平滑度较低,但灵敏度较高 N值的选取:一般流量,N=12;压力:N=4 B、优点: 适用于对一般具有随机干扰的信号进行滤波 这样信号的特点是有一个平均值,信号在某一数值范围附近上下波动 C、缺点: 对于测量速度较慢或要求数据计算速度较快的实时控制不适用 比较浪费RAM 4、递推平均滤波法(又称滑动平均滤波法) A、方法: 把连续取N个采样值看成一个队列 队列的长度固定为N 每次采样到一个新数据放入队尾,并扔掉原来队首的一次数据.(先进先出原则) 把队列中的N个数据进行算术平均运算,就可获得新的滤波结果 N值的选取:流量,N=12;压力:N=4;液面,N=4~12;温度,N=1~4 B、优点: 对周期性干扰有良好的抑制作用,平滑度高 适用于高频振荡的系统 C、缺点: 灵敏度低 对偶然出现的脉冲性干扰的抑制作用较差 不易消除由于脉冲干扰所引起的采样值偏差 不适用于脉冲干扰比较严重的场合 比较浪费RAM 5、中位值平均滤波法(又称防脉冲干扰平均滤波法) A、方法: 相当于“中位值滤波法”+“算术平均滤波法” 连续采样N个数据,去掉一个最大值和一个最小值 然后计算N-2个数据的算术平均值 N值的选取:3~14 B、优点: 融合了两种滤波法的优点 对于偶然出现的脉冲性干扰,可消除由于脉冲干扰所引起的采样值偏差 C、缺点: 测量速度较慢,和算术平均滤波法一样 比较浪费RAM 6、限幅平均滤波法 A、方法: 相当于“限幅滤波法”+“递推平均滤波法” 每次采样到的新数据先进行限幅处理, 再送入队列进行递推平均滤波处理 B、优点: 融合了两种滤波法的优点 对于偶然出现的脉冲性干扰,可消除由于脉冲干扰所引起的采样值偏差 C、缺点: 比较浪费RAM 7、一阶滞后滤波法 A、方法: 取a=0~1 本次滤波结果=(1-a)*本次采样值+a*上次滤波结果 B、优点: 对周期性干扰具有良好的抑制作用 适用于波动频率较高的场合 C、缺点: 相位滞后,灵敏度低 滞后程度取决于a值大小 不能消除滤波频率高于采样频率的1/2的干扰信号 8、加权递推平均滤波法 A、方法: 是对递推平均滤波法的改进,即不同时刻的数据加以不同的权 通常是,越接近现时刻的数据,权取得越大。 给予新采样值的权系数越大,则灵敏度越高,但信号平滑度越低 B、优点: 适用于有较大纯滞后时间常数的对象 和采样周期较短的系统 C、缺点: 对于纯滞后时间常数较小,采样周期较长,变化缓慢的信号 不能迅速反应系统当前所受干扰的严重程度,滤波效果差 9、消抖滤波法 A、方法: 设置一个滤波计数器 将每次采样值与当前有效值比较: 如果采样值=当前有效值,则计数器清零 如果采样值当前有效值,则计数器+1,并判断计数器是否>=上限N(溢出) 如果计数器溢出,则将本次值替换当前有效值,并清计数器 B、优点: 对于变化缓慢的被测参数有较好的滤波效果, 可避免在临界值附近控制器的反复开/关跳动或显示器上数值抖动 C、缺点: 对于快速变化的参数不宜 如果在计数器溢出的那一次采样到的值恰好是干扰值,则会将干扰值当作有效值导入系统 10、限幅消抖滤波法 A、方法: 相当于“限幅滤波法”+“消抖滤波法” 先限幅,后消抖 B、优点: 继承了“限幅”和“消抖”的优点 改进了“消抖滤波法”中的某些缺陷,避免将干扰值导入系统 C、缺点: 对于快速变化的参数不宜
卡尔曼滤波是一种用于估计系统状态的算法,它可以通过融合传感器测量值和系统模型来提供更准确的状态估计。在C++中,可以使用Eigen库来实现卡尔曼滤波算法。 以下是一个简单的卡尔曼滤波C++实现的示例: ```cpp #include <iostream> #include <Eigen/Dense> using namespace Eigen; class KalmanFilter { public: KalmanFilter() { // 初始化状态向量 x = Vector2d(0, 0); // 初始化状态协方差矩阵 P = Matrix2d::Identity(); // 初始化过程噪声协方差矩阵 Q = Matrix2d::Identity(); // 初始化观测噪声协方差矩阵 R = Matrix2d::Identity(); // 初始化状态转移矩阵 A = Matrix2d::Identity(); // 初始化观测矩阵 H = Matrix2d::Identity(); } void predict() { // 预测步骤 x = A * x; P = A * P * A.transpose() + Q; } void update(const Vector2d& z) { // 更新步骤 Vector2d y = z - H * x; Matrix2d S = H * P * H.transpose() + R; Matrix2d K = P * H.transpose() * S.inverse(); x = x + K * y; P = (Matrix2d::Identity() - K * H) * P; } private: Vector2d x; // 状态向量 Matrix2d P; // 状态协方差矩阵 Matrix2d Q; // 过程噪声协方差矩阵 Matrix2d R; // 观测噪声协方差矩阵 Matrix2d A; // 状态转移矩阵 Matrix2d H; // 观测矩阵 }; int main() { KalmanFilter kf; // 测量值 Vector2d z(1, 1); // 预测步骤 kf.predict(); // 更新步骤 kf.update(z); // 输出估计的状态向量 std::cout << "Estimated state: " << kf.x.transpose() << std::endl; return 0; } ``` 这个示例实现了一个简单的二维卡尔曼滤波器。在`KalmanFilter`类中,`predict`函数用于进行预测步骤,`update`函数用于进行更新步骤。在`main`函数中,首先创建了一个`KalmanFilter`对象,然后给定了一个测量值`z`,接着进行预测和更新步骤,并输出估计的状态向量。 希望这个示例能够帮助你理解卡尔曼滤波C++实现。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值