C语言实现巴特沃斯低通滤波器

本文C语言的实现公式和思路参考自: 数字信号处理|Matlab设计巴特沃斯低通滤波器(冲激响应不变法和双线性变换法)
还有 北京交通大学 陈后金教授 和 华东理工大学 万永菁教授的网课


设计数字巴特沃斯低通滤波器,设计指标如下:
通带截止频率为 200 Hz
阻带截止频率为 400 Hz
通带最大衰减为 1 db
阻带最小衰减为 30 db
采样频率为 1000 Hz

我使用了 3 种方法实现,两种是借助 matlab 实现,最后一种是完全使用 c 语言实现,3种方式得到的结果均相同,我的C语言实现可以给定任何指标来得出和 matlab 一样的结果。
我使用 C 语言实现了 matlab 的 buttord 和 bilinear 函数, buttap 函数并没有以函数形式实现,zp2tf函数 和 lp2lp函数是放在一起实现的。
目前 C 语言版本只是很潦草的实现了一下,主要实现了功能,内存的释放写的非常乱和随意。后面会多写几篇文章把 matlab 的每一个函数都以 C++ 的方式单独实现,因为 C语言要自己构造数据结构,还要很麻烦的内存管理,不适合写这些代码。

matlab 代码实现

方法一:

代码:

clear,clc,close;
%1.数字滤波器的技术指标要求
ap = 1;%通带最大衰减
as = 30;%阻带最小衰减
fp = 200;%通带截止频率
fs = 400;%阻带截止频率
Fs = 1000;%抽样间隔
T = 1/Fs;
 
%2.将数字指标转化成模拟滤波器指标
wp=(2*pi*fp)/Fs;
ws=(2*pi*fs)/Fs;

% 数字指标转模拟指标 预畸变,前面要× (2/T)
wap=2*Fs*tan(wp/2);
was=2*Fs*tan(ws/2);
 
%3.设计模拟滤波器
[N,wac]=buttord(wap,was,ap,as,'s');% N为阶数,wac为3dB截止频率, 's'表示设计的是模拟滤波器
disp("N="+N);
disp("wac="+wac);
[z,p,k]=buttap(N);% 创建巴特沃斯低通滤波器 z零点p极点k增益
[Bap,Aap]=zp2tf(z,p,k);% 由零极点和增益确定归一化Han(s)系数
[Bbs,Abs]=lp2lp(Bap,Aap,wac);% 低通到低通 计算去归一化Ha(s)
[B,A] = bilinear(Bbs,Abs,Fs); % 模拟域到数字域:双线性不变法
disp("B="+B);
disp("A="+A);
[H1,w] = freqz(B,A);% 根据H(z)求频率响应特性
 
%绘制数字滤波器频响幅度谱
figure(2);
f=w*Fs/(2*pi);
subplot(211);
plot(f,20*log10(abs(H1))); % 绘制幅度响应
grid on;
title('双线性变换法——巴特沃斯BLPF(幅度)');
xlabel('频率/Hz');
axis([0 500 -83 5]);
ylabel('H1幅值/dB');
subplot(212);
plot(f,unwrap(angle(H1)));% 绘制相位响应
grid on;
xlabel('频率/Hz');
ylabel('角度/Rad')
title('双线性变换法——巴特沃斯BLPF(相位)');

结果:

在这里插入图片描述

方法二:

代码:

%数字低通滤波器指标
fp = 200;%通带截止频率 hz
fs = 400;%阻带截止频率 hz
Ap=1; %通带最大衰减 db
As=30;%阻带最小衰减 db
Fs=1000;%采样频率 hz

%转化为模拟滤波器指标
wp=2*pi*fp/Fs;%通带截止频率 rad
ws=2*pi*fs/Fs;%阻带截止频率 rad
disp("模拟滤波器通带截止频率 = "+wp);
disp("模拟滤波器阻带截止频率 = "+ws);

%数字指标转换为模拟指标要进行预畸变,前面要× (2/T), 乘以 2/T,就是乘以 2*Fs
wap=2*Fs*tan(wp/2);
was=2*Fs*tan(ws/2);

%计算满足模拟低通滤波器指标的最低阶数 N 和 截止频率 wac
[N,wac]=buttord(wap,was,Ap,As,'s');
disp("模拟低通滤波器最低阶数 = "+N);
disp("模拟低通滤波器截止频率 = "+wac);

%计算模拟滤波器系统函数 H(s) 的分子和分母系数,H(s)就是拉普拉斯变换
%numa 是 H(s) 的分子系数,dena 是 H(s) 的分母系数
[numa,dena]=butter(N,wac,'s');
disp("模拟低通滤波器 H(s) 的分子和分母系数:");
disp("分子系数:");
disp(numa);
disp("分母系数:");
disp(dena);

%计算数字滤波器系统函数 H(z) 的分子和分母系数,H(z)就是 z 变换
%numd 是 H(z) 的分子系数,dend 是 H(z) 的分母系数
%[numd,dend]=impinvar(numa,dena,Fs);
[numd,dend]=bilinear(numa,dena,Fs);
disp("数字低通滤波器 H(s) 的分子和分母系数:");
disp("分子系数:");
disp(numd);
disp("分母系数:");
disp(dend);

%画频率响应
w=linspace(0,pi,1024);
h=freqz(numd,dend,w);

%归一化振幅
norm=max(abs(h));
numd=numd/norm;

figure(3);
subplot(311);
plot(w/pi,20*log10(abs(h/norm)));
xlabel('归一化频率');
ylabel('增益 dB');

subplot(312);
plot(w,20*log10(abs(h/norm)));
xlabel('角频率 rad');
ylabel('增益 in dB');

subplot(313);
plot(w/(2*pi)*Fs, 20*log10(abs(h/norm)));
xlabel('频率 Hz');
ylabel('增益  dB');

%computer Ap As of the designed filter
w=[wp ws];
h=freqz(numd,dend,w);
disp("h="+h);
fprintf('Ap= %.4f\n',-20*log10( abs(h(1))));
fprintf('As= %.4f\n',-20*log10( abs(h(2))));

结果:

在这里插入图片描述

方法一 和 方法二 得到的结果相同

fdatool 实现

幅频响应

在这里插入图片描述

相频响应

在这里插入图片描述

H(z) 的分子和分母系数

在这里插入图片描述

C语言实现

代码:

#include <stdio.h>
#include <math.h>
#include <malloc.h>
#include <string.h>

#define pi ((double)3.141592653589793)

struct DESIGN_SPECIFICATION
{
    
    
	// 数字通带截止频率 Hz
	double digital_passband_cutoff_frequency;
	// 数字阻带截止频率 Hz
	double digital_stopband_cutoff_frequency;
	// 通带最大衰减 db
	int passband_max_attenuation;
	// 阻带最小衰减 db
	int stopband_min_attenuation;
	// 采样频率 Hz
	int fs;
};

typedef struct complex
{
    
    
	double real;
	double img;
}Complex;

typedef struct node
{
    
    
	int pow; // 指数
	complex* coeff; // 系数
	struct node* next;
}Node;

typedef struct linklist
{
    
    
	Node* head;
}Linklist;

/*复数加法*/
int complex_add(Complex* input_1, Complex* input_2, Complex* output)
{
    
    
	if (input_1 == NULL || input_2 == NULL || output == NULL)
	{
    
    
		return -1;
	}

	output->real = input_1->real + input_2->real;
	output->img = input_1->img + input_2->img;

	return 0;
}

/*复数乘法*/
int complex_mul(Complex* input_1, Complex* input_2, Complex* output)
{
    
    
	if (input_1 == NULL || input_2 == NULL || output == NULL)
	{
    
    
		return -1;
	}
	output->real = input_1->real * input_2->real - input_1->img * input_2->img;
	output->img = input_1->real * input_2->img + input_1->img * input_2->real;

	return 0;
}

int node_mul(Node* input_1, Node* input_2, Node* output)
{
    
    
	if (input_1 == NULL || input_2 == NULL || output == NULL)
	{
    
    
		return -1;
	}

	// 两个节点系数相乘用 mul 函数
	Complex* coeff = (Complex*)malloc(sizeof(Complex));
	int result = complex_mul(input_1->coeff, input_2->coeff, coeff);
	if (result == -1)
	{
    
    
		free(coeff);
		coeff = NULL;
		return -1;
	}
	output->coeff = coeff;

	// 两个节点的指数相加
	int pow = input_1->pow + input_2->pow;
	output->pow = pow;

	return 0;
}

int insert(Linklist* list, Node* node)
{
    
    
	if (list == NULL || node == NULL)
	{
    
    
		return -1;
	}

	Node* cur = list->head;
	Node* pre = NULL;

	while (cur != NULL)
	{
    
    
		// 如果当前节点的指数 大于 node 的指数,那么就要将 cur 指向下一个节点
		if (cur->pow > node->pow)
		{
    
    
			pre = cur;
			cur = cur->next;
		}

		// 如果当前节点的指数 小于 node 的指数,那么就要将 cur 插入到当前节点之前
		else if (cur->pow < node->pow)
		{
    
    
			if (pre == NULL)
			{
    
    
				node->next = list->head;
				list->head = node;
				return 0;
			}
			pre->next = node;
			node->next = cur;
			return 0;
		}

		// 如果当前节点的指数 等于 node 的指数,那么就要将这两个节点相加
		else
		{
    
    
			// 系数相加
			int ret = complex_add(cur->coeff, node->coeff, cur->coeff);
			if (ret == -1)
			{
    
    
				return -1;
			}

			free(node);
			node = NULL;
			return 0;
		}
	}

	// 如果当前节点为空,说明到了链表末尾, 将节点插到前一个节点的后面
	if (pre == NULL)
	{
    
    
		list->head = node;
		return 0;
	}
	pre->next = node;
	return 0;
}

int list_mul(Linklist* input_list1, Linklist* input_list2, Linklist* output_list)
{
    
    
	if (input_list1 == NULL || input_list2 == NULL || output_list == NULL)
	{
    
    
		return -1;
	}

	// 链表1 的 每一个节点与 链表2 相乘
	Node* input_1 = input_list1->head;
	while (input_1 != NULL)
	{
    
    
		Node* input_2 = input_list2->head;
		if (input_2 == NULL)
		{
    
    
			break;
		}
		while (input_2 != NULL)
		{
    
    
			Node* output = (Node*)malloc(sizeof(Node));
			output->next = NULL;
			output->coeff = NULL;
			int ret = node_mul(input_1, input_2, output);
			if (ret == -1)
			{
    
    
				return -1;
			}
			ret = insert(output_list, output);
			if (ret == -1)
			{
    
    
				return -1;
			}
			input_2 = input_2->next;
		}

		input_1 = input_1->next;
	}
	return 0;
}

int list_add(Linklist* input_list1, Linklist* input_list2, Linklist* output_list)
{
    
    
	if (input_list1 == NULL || input_list2 == NULL || output_list == NULL)
	{
    
    
		return -1;
	}

	int ret = 0;
	bool insert_flag = false;
	// 链表1 的 每一个节点与 链表2 相加
	Node* input_1 = input_list1->head;
	while (input_1 != NULL)
	{
    
    
		Node* input_2 = input_list2->head;
		while (input_2 != NULL)
		{
    
    
			if (input_1->pow == input_2->pow)
			{
    
    
				Node* node = (Node*)malloc(sizeof(Node));
				node->next = NULL;
				node->coeff = (Complex*)malloc(sizeof(Complex));
				ret = complex_add(input_1->coeff, input_2->coeff, node->coeff);
				if (ret == -1)
				{
    
    
					return -1;
				}
				node->pow = input_1->pow;
				ret = insert(output_list, node);
				if (ret == -1)
				{
    
    
					return -1;
				}
				insert_flag = true;
				break;
			}
			else
			{
    
    
				input_2 = input_2->next;
			}
		}

		if (insert_flag == false)
		{
    
    
			// 说明遍历了 input_list2 没找到与 input_1 节点相同的 pow 
			// 此时就构造一个和 input_1 相同的节点,然后把它 insert 到 output_list 
			Node* node = (Node*)malloc(sizeof(Node));
			node->next = NULL;
			node->coeff = (Complex*)malloc(sizeof(Complex));
			node->coeff = input_1->coeff;
			node->pow = input_1->pow;
			insert(output_list, node);
		}
		insert_flag = false;
		input_1 = input_1->next;
	}
	return 0;
}

void destoryList(Linklist* list)
{
    
    
	if (list == NULL)
	{
    
    
		return;
	}

	Node* node = list->head;
	while (node != NULL)
	{
    
    
		// 先销毁 Node 内部的 complex
		if (node->coeff != NULL)
		{
    
    
			free(node->coeff);
			node->coeff = NULL;
		}

		Node* n = node;
		node = node->next;

		// 再销毁 Node 本身
		free(n);
		n = NULL;
	}
}

// 构造一个Linklist,第一个节点是 s (系数为(1+j0),指数为1),第二个节点是 complex c(系数为(complex c),指数为0)
int initList(Linklist* list, Complex* c)
{
    
    
	if (list == NULL || c == NULL)
	{
    
    
		return -1;
	}

	Node* node = (Node*)malloc(sizeof(Node));
	node->next = NULL;
	Complex* coeff = (Complex*)malloc(sizeof(Complex));
	coeff->real = 1.0;
	coeff->img = 0.0;
	node->coeff = coeff;
	node->pow = 1;

	int ret = insert(list, node);
	if (ret == -1)
	{
    
    
		return -1;
	}

	Node* node2 = (Node*)malloc(sizeof(Node));
	node2->next = NULL;
	node2->coeff = c;
	node2->pow = 0;

	ret = insert(list, node2);
	if (ret == -1)
	{
    
    
		return -1;
	}
	return 0;
}

int copyList(Linklist* src, Linklist* dst)
{
    
    
	if (dst == NULL)
	{
    
    
		return -1;
	}
	if (src == NULL)
	{
    
    
		return 0;
	}
	Node* node = src->head;
	while (node != NULL)
	{
    
    
		Node* copy_node = (Node*)malloc(sizeof(Node));
		Complex* copy_coeff = (Complex*)malloc(sizeof(Complex));
		if (node->coeff == NULL)
		{
    
    
			return -1;
		}
		copy_coeff->real = node->coeff->real;
		copy_coeff->img = node->coeff->img;
		copy_node->coeff = copy_coeff;
		copy_node->next = NULL;
		copy_node->pow = node->pow;
		insert(dst, copy_node);

		node = node->next;
	}
	return 0;
}

int createElement(Complex* c, Linklist* list)
{
    
    
	if (c == NULL || list == NULL)
	{
    
    
		return -1;
	}

	Node* node_s = (Node*)malloc(sizeof(Node));
	node_s->next = NULL;
	node_s->coeff = (Complex*)malloc(sizeof(Complex));
	node_s->coeff->real = 1.0;
	node_s->coeff->img = 0.0;
	node_s->pow = 1;

	Node* node_poly = (Node*)malloc(sizeof(Node));
	node_poly->next = NULL;
	node_poly->coeff = c;
	node_poly->coeff->real = -1 * node_poly->coeff->real;
	node_poly->coeff->img = -1 * node_poly->coeff->img;
	node_poly->pow = 0;

	node_s->next = node_poly;
	list->head = node_s;
	return 0;
}

int createElementList(int N, Linklist* input, Linklist** output)
{
    
    
	if (N <=0 || input == NULL || output == NULL)
	{
    
    
		return -1;
	}
	Node* node = input->head;
	int ret = 0;
	for (int i = 0; i < N; i++)
	{
    
    
		if (output[i] == NULL)
		{
    
    
			return -1;
		}
		ret = createElement(node->coeff, output[i]);
		if (ret == -1)
		{
    
    
			return -1;
		}
		node = node->next;
	}
	printf("===========================================\n");
	for (int i = 0; i < N; i++)
	{
    
    
		Node* node = output[i]->head;
		printf("系数:%lf  %lf , 指数:%d ;", node->coeff->real, node->coeff->img, node->pow);
		printf("系数:%lf  %lf , 指数:%d \n", node->next->coeff->real, node->next->coeff->img, node->next->pow);
	}
	return 0;
}

// wap 为模拟低通滤波器通带截止频率 Hz
// was 为模拟低通滤波器阻带截止频率 Hz
// ap 为模拟低通滤波器通带最大衰减 db
// as 为模拟低通滤波器阻带最小衰减 db
// N 为需要计算的模拟巴特沃斯低通滤波器的阶数
// wc 为需要计算的模拟巴特沃斯低通滤波器的3db截止频率
bool Buttord(double wap, double was, int ap, int as, int* N, double* wc)
{
    
    
	// wap was ap as 都不能 <= 0
	if (wap <= 0.0001 || was <= 0.0001 || ap <= 0.0001 || as <= 0.0001 || N == NULL || wc == NULL)
	{
    
    
		return false;
	}
	double ksp = sqrt((pow(10, 0.1*as) - 1) / (pow(10, 0.1*ap) - 1));
	// 计算归一化频率
	double lambdasp = was / wap;
	*N = ceil(log10(ksp) / log10(lambdasp));
	// 使用双线性变换法,应用阻带指标 was
	*wc = was * pow(pow(10, 0.1 * as) - 1, -1.0 / (2 * *N));
	return true;
}

bool Butter(int N, double cutoff, Linklist* hs_den_list)
{
    
    
	if (N <= 0 || hs_den_list == NULL)
	{
    
    
		return false;
	}

	bool ret = false;

	Complex** poles = (Complex**)malloc(sizeof(Complex) * N);

	for (int k = 0, i = 0; k <= ((2 * N) - 1); k++)
	{
    
    
		if (cutoff * cos(pi * 0.5 + pi * (2 * k + 1) / (2 * N)) < 0)
		{
    
    
			poles[i] = (Complex*)malloc(sizeof(Complex));
			printf("系数:%.15lf   %.15lf \n", cos(pi * 0.5 + pi * (2 * k + 1) / (2 * N)), sin(pi * 0.5 + pi * (2 * k + 1) / (2 * N)));
			poles[i]->real = cutoff * cos(pi * 0.5 + pi * (2 * k + 1) / (2 * N));
			poles[i]->img = cutoff * sin(pi * 0.5 + pi * (2 * k + 1) / (2 * N));
			i++;
			if (i == N) break;
		}
	}

	printf("Pk =   \n");
	for (int i = 0; i < N; i++)
	{
    
    
		printf("(%.15lf + %.15lf i) \n", poles[i]->real, poles[i]->img);
	}

	// 构造 N 个链表(有几个极点就构造几个链表)
	Linklist** listArr = (Linklist**)malloc(sizeof(Linklist) * N);
	for (int i = 0; i < N; i++)
	{
    
    
		Linklist* list = (Linklist*)malloc(sizeof(Linklist));
		list->head = NULL;
		// 构造一个Linklist,第一个节点是 s (系数为(1+j0),指数为1),第二个节点是 complex c(系数为(complex c),指数为0)
		initList(list, poles[i]);
		listArr[i] = list;
	}

	printf("============= 相乘前H(s)分母的元素 =============\n");
	for (int i = 0; i < N; i++)
	{
    
    
		Linklist* list = listArr[i];
		Node* node = list->head;
		printf("(系数:%.15lf , %.15f  指数:%d ;", node->coeff->real, node->coeff->img, node->pow);

		node = list->head->next;
		printf(" 系数:%.15lf , %.15f  指数:%d) \n", node->coeff->real, node->coeff->img, node->pow);
	}

	for (int i = 0; i < N; i++)
	{
    
    
		Node* coeff_node = listArr[i]->head->next;
		if (i == 0)
		{
    
    
			hs_den_list->head = coeff_node;
			continue;
		}
		Node* node = hs_den_list->head;
		Node* pre = NULL;
		while (node != NULL)
		{
    
    
			pre = node;
			node = node->next;
		}
		pre->next = coeff_node;
	}
	return true;
}

// 构造 (1-z^-1)^N
int caul_1_sub_z_n(int N, Linklist* result)
{
    
    
	if (N < 0 || result == NULL)
	{
    
    
		return -1;
	}
	// 先构造 1-z^-1
	// 构造节点 1 ,存储在 node_1
	Node* node_1 = (Node*)malloc(sizeof(Node));
	node_1->next = NULL;
	node_1->coeff = (Complex*)malloc(sizeof(Complex));
	node_1->coeff->real = 1.0;
	node_1->coeff->img = 0.0;
	node_1->pow = 0;

	if (N == 0)
	{
    
    
		result->head = node_1;
		return 0;
	}

	// 构造节点 -z^-1 ,存储在 node_z
	Node* node_z = (Node*)malloc(sizeof(Node));
	node_z->next = NULL;
	node_z->coeff = (Complex*)malloc(sizeof(Complex));
	node_z->coeff->real = -1.0;
	node_z->coeff->img = 0.0;
	node_z->pow = -1;

	// 节点 z^-1 连在 1 的后面,这样就成了 1 - z^-1
	node_1->next = node_z;

	if (N == 1)
	{
    
    
		result->head = node_1;
		return 0;
	}

	// 1-z^-1 存储在链表 list_1_sub_z
	Linklist* list_1_sub_z = (Linklist*)malloc(sizeof(Linklist));
	list_1_sub_z->head = node_1;

	// 将 1-z^-1 乘以 N 次
	Linklist** mul_result = (Linklist**)malloc(sizeof(Linklist)*(N-1));
	mul_result[0] = (Linklist*)malloc(sizeof(Linklist));
	mul_result[0]->head = NULL;
	// 计算 (1-z^-1)^2 ,结果存储在 mul_result[0]
	int ret = list_mul(list_1_sub_z, list_1_sub_z, mul_result[0]);

	for (int i = 0; i < (N-2); i++)
	{
    
    
		mul_result[i+1] = (Linklist*)malloc(sizeof(Linklist));
		mul_result[i+1]->head = NULL;
		ret = list_mul(mul_result[i],list_1_sub_z, mul_result[i+1]);
		if (ret == -1)
		{
    
    
			return -1;
		}
	}
	
	// 将 (1-z^-1)^N 的结果从 mul_result[N-2] 拷贝到 result
	ret = copyList(mul_result[N-2], result);

	for (int i = 0; i < (N - 1); i++)
	{
    
    
		destoryList(mul_result[i]);
		mul_result[i] = NULL;
	}
	return ret;
}

// 构造 (1+z^-1)^N
int caul_1_add_z_n(int N, Linklist* result)
{
    
    
	if (N < 0 || result == NULL)
	{
    
    
		return -1;
	}
	// 先构造 1+z^-1
	// 构造节点 1 ,存储在 node_1
	Node* node_1 = (Node*)malloc(sizeof(Node));
	node_1->next = NULL;
	node_1->coeff = (Complex*)malloc(sizeof(Complex));
	node_1->coeff->real = 1.0;
	node_1->coeff->img = 0.0;
	node_1->pow = 0;

	if (N == 0)
	{
    
    
		result->head = node_1;
		return 0;
	}

	// 构造节点 z^-1 ,存储在 node_z
	Node* node_z = (Node*)malloc(sizeof(Node));
	node_z->next = NULL;
	node_z->coeff = (Complex*)malloc(sizeof(Complex));
	node_z->coeff->real = 1.0;
	node_z->coeff->img = 0.0;
	node_z->pow = -1;

	// 节点 z^-1 连在 1 的后面,这样就成了 1+z^-1
	node_1->next = node_z;

	if (N == 1)
	{
    
    
		result->head = node_1;
		return 0;
	}

	// 1+z^-1 存储在链表 list_1_add_z
	Linklist* list_1_add_z = (Linklist*)malloc(sizeof(Linklist));
	list_1_add_z->head = node_1;

	// 将 1+z^-1 乘以 N 次
	Linklist** mul_result = (Linklist**)malloc(sizeof(Linklist) * (N - 1));
	mul_result[0] = (Linklist*)malloc(sizeof(Linklist));
	mul_result[0]->head = NULL;
	// 计算 (1+z^-1)^2 ,结果存储在 mul_result[0]
	int ret = list_mul(list_1_add_z, list_1_add_z, mul_result[0]);

	for (int i = 0; i < (N - 2); i++)
	{
    
    
		mul_result[i + 1] = (Linklist*)malloc(sizeof(Linklist));
		mul_result[i + 1]->head = NULL;
		ret = list_mul(mul_result[i], list_1_add_z, mul_result[i + 1]);
		if (ret == -1)
		{
    
    
			return -1;
		}
	}

	// 将 (1+z^-1)^N 的结果从 mul_result[N-2] 拷贝到 result
	ret = copyList(mul_result[N - 2], result);
	for (int i = 0; i < (N - 1); i++)
	{
    
    
		destoryList(mul_result[i]);
		mul_result[i] = NULL;
	}
	return ret;
}

// 将 hs_den_list 中的 s 变成 (2/T)*(1-z^-1)/(1+z^-1) 就得到 H(z)
// 得到 hz_den_list 的方法是,将 hs_den_list 中的 s 变成 (2/T)*(1-z^-1)
// 得到 hz_mol_list 的方法是 计算 (1+z^-1)^N
int Bilinear(int N,
	double hs_mol_coeff,
	Linklist* hs_den_list,
	Linklist* hz_den_list,
	Linklist* hz_mol_list,
	int fs)
{
    
    
	if (N <= 0 || hs_den_list == NULL || hz_den_list == NULL || hz_mol_list == NULL || fs <= 0)
	{
    
    
		return -1;
	}
	int ret = 0;

	//一、计算 H(z) 的分母,结果存储在 hz_den_list
	Node* node = hs_den_list->head;
	Linklist** mul_reult_list = (Linklist**)malloc(sizeof(Linklist) * (N+1));
	int index = 0;
	while (node != NULL)
	{
    
    
		// 1. 构造 a*(2/T)^pow,结果存放在 list_coeff
		Linklist* list_coeff = (Linklist*)malloc(sizeof(Linklist));
		list_coeff->head = NULL;

		Complex* c = node->coeff;
		Node* new_coeff_node = (Node*)malloc(sizeof(Node));
		new_coeff_node->next = NULL;
		Complex* new_c = (Complex*)malloc(sizeof(Complex));
		Complex* tmp = (Complex*)malloc(sizeof(Complex));
		tmp->img = 0.0;
		// 计算 (2/T)^pow
		tmp->real = pow(2.0*fs, node->pow);
		// 计算 a*(2/T)^pow
		ret = complex_mul(c, tmp, new_c);
		printf("系数: %.15lf ,指数 = %d,新的系数:%.15lf\n", node->coeff->real, node->pow, new_c->real);
		if (ret == -1)
		{
    
    
			free(new_coeff_node);
			new_coeff_node = NULL;
			free(new_c);
			new_c = NULL;
			free(tmp);
			tmp = NULL;
			return -1;
		}
		new_coeff_node->coeff = new_c;
		new_coeff_node->pow = 0;
		list_coeff->head = new_coeff_node;

		// 2. 构造 (1-z^-1)^pow, 结果存放在 list_1_sub_z_pow
		Linklist * list_1_sub_z_pow = (Linklist*)malloc(sizeof(Linklist));
		list_1_sub_z_pow->head = NULL;
		ret = caul_1_sub_z_n(node->pow, list_1_sub_z_pow);
		if (ret == -1)
		{
    
    
			return -1;
		}

		// 3. 构造 (1+z^-1)^(N-pow), 结果存放在 list_1_add_z_N_pow
		Linklist* list_1_add_z_N_pow = (Linklist*)malloc(sizeof(Linklist));
		list_1_add_z_N_pow->head = NULL;
		ret = caul_1_add_z_n(N - node->pow, list_1_add_z_N_pow);
		if (ret == -1)
		{
    
    
			return -1;
		}

		// 4. 计算 a*(2/T)^pow * (1-z^-1)^pow * (1+z^-1)^(N-pow), 结果存放在 mul_reult_list[index]
		Linklist* list_result_1 = (Linklist*)malloc(sizeof(Linklist));
		list_result_1->head = NULL;
		// 4.1 计算 a*(2/T)^pow * (1-z^-1)^pow, 结果存放在 list_result_1
		ret = list_mul(list_coeff, list_1_sub_z_pow, list_result_1);
		if (ret == -1)
		{
    
    
			return -1;
		}
		mul_reult_list[index] = (Linklist*)malloc(sizeof(Linklist));
		mul_reult_list[index]->head = NULL;
		// 4.2 计算 a*(2/T)^pow * (1-z^-1)^pow * (1+z^-1)^(N-pow), 结果存放在 mul_reult_list[index]
		ret = list_mul(list_result_1, list_1_add_z_N_pow, mul_reult_list[index]);
		if (ret == -1)
		{
    
    
			return -1;
		}
		Node* tmp_node = mul_reult_list[index]->head;
		while (tmp_node != NULL)
		{
    
    
			printf("系数:%lf  %lf , 指数:%d \n", tmp_node->coeff->real, tmp_node->coeff->img, tmp_node->pow);
			tmp_node = tmp_node->next;
		}
		tmp_node = NULL;
		destoryList(list_coeff);
		destoryList(list_1_sub_z_pow);
		destoryList(list_1_add_z_N_pow);
		destoryList(list_result_1);
		free(tmp);
		tmp = NULL;
		list_coeff = NULL;
		list_1_sub_z_pow = NULL;
		list_1_add_z_N_pow = NULL;
		list_result_1 = NULL;
		++index;
		node = node->next;
	}
	
	for (int i = 0; i < (index-1); i+=2)
	{
    
    
		ret = list_add(mul_reult_list[i], mul_reult_list[i + 1], hz_den_list);
		if (ret == -1)
		{
    
    
			return -1;
		}
	}

	// 将分母各项的系数都除以最高次幂的系数,使得最高次幂对应的系数为1
	node = hz_den_list->head;
	double max_pow_coeff = node->coeff->real;
	while (node != NULL)
	{
    
    
		node->coeff->real = node->coeff->real / max_pow_coeff;
		node = node->next;
	}

	//二、计算 H(z) 的分子 (1+z^-1)^N,结果存储在 hz_mol_list
	ret = caul_1_add_z_n(N, hz_mol_list);
	if (ret == -1)
	{
    
    
		return -1;
	}
	// 然后给 hz_mol_list 的每一项乘以 H(s) 的分子系数 hs_mol_coeff 再除以 max_pow_coeff
	node = hz_mol_list->head;
	while (node != NULL)
	{
    
    
		node->coeff->real = node->coeff->real * hs_mol_coeff / max_pow_coeff;
		node = node->next;
	}
	node = NULL;
	mul_reult_list = NULL;
	return 0;
}

int mul_element(int N, Linklist** input, Linklist* output)
{
    
    
	if (N <= 0 || input == NULL || output == NULL)
	{
    
    
		printf("error: mul_element N <= 0 || input == NULL || output == NULL\n");
		return -1;
	}
	if (N == 1)
	{
    
    
		if (output == NULL)
		{
    
    
			printf("error: output[0] 为 NULL,无法赋值\n");
			return -1;
		}
		output = input[0];
		return 0;
	}
	else
	{
    
    
		Linklist** mul_list_arr = (Linklist**)malloc(sizeof(Linklist)*(N-1));
		mul_list_arr[0] = (Linklist*)malloc(sizeof(Linklist));
		mul_list_arr[0]->head = NULL;
		int ret = list_mul(input[0], input[1], mul_list_arr[0]);
		if (ret == -1)
		{
    
    
			printf("error: list_mul(input[0], input[1], mul_list_arr[0]) \n");
			return -1;
		}
		for (int i = 0; i < (N - 2); i++)
		{
    
    
			mul_list_arr[i + 1] = (Linklist*)malloc(sizeof(Linklist));
			mul_list_arr[i + 1]->head = NULL;
			
			ret = list_mul(mul_list_arr[i], input[i + 2], mul_list_arr[i + 1]);
			if (ret == -1)
			{
    
    
				printf("error: list_mul(mul_list_arr[%d], input[%d], mul_list_arr[%d]) \n", i, i + 2, i + 1);
				return -1;
			}
		}

		ret = copyList(mul_list_arr[N-2], output);
		if (ret == -1)
		{
    
    
			printf("error: mul_element2 copyList 出错 \n");
		}
		for (int i = 0; i < (N-1); i++)
		{
    
    
			destoryList(mul_list_arr[i]);
			mul_list_arr[i] = NULL;
		}
		return 0;
	}
}

int main(void)
{
    
    
	struct DESIGN_SPECIFICATION IIR_Filter;
	//Analog passband cutoff frequency

	//1.数字滤波器的技术指标
	IIR_Filter.digital_passband_cutoff_frequency = 200; // Hz
	IIR_Filter.digital_stopband_cutoff_frequency = 400;// Hz
	IIR_Filter.passband_max_attenuation = 1; // db
	IIR_Filter.stopband_min_attenuation = 30;// db
	IIR_Filter.fs = 1000;// Hz

	//2.将数字指标转化成模拟滤波器技术指标
	double analog_passband_cutoff_frequency = (2 * pi * IIR_Filter.digital_passband_cutoff_frequency) / IIR_Filter.fs;
	double analog_stopband_cutoff_frequency = (2 * pi * IIR_Filter.digital_stopband_cutoff_frequency) / IIR_Filter.fs;
	//printf("wp = %lf, ws = %lf\n", analog_passband_cutoff_frequency, analog_stopband_cutoff_frequency);

	//3.数字指标转模拟指标 预畸变,前面要× (2/T)
	double wap = 2.0 * IIR_Filter.fs * tan(analog_passband_cutoff_frequency / 2);
	double was = 2.0 * IIR_Filter.fs * tan(analog_stopband_cutoff_frequency / 2);
	//printf("wap = %lf, was = %lf\n", wap, was);

	//4.计算巴特沃斯滤波器阶数 和 3db截止频率
	int* N = (int*)malloc(sizeof(int));
	double* wc = (double*)malloc(sizeof(double));
	bool ret = Buttord(wap,
					was,
					IIR_Filter.passband_max_attenuation,
					IIR_Filter.stopband_min_attenuation,
					N,
					wc);
	if (ret == false)
	{
    
    
		printf("Buttord error!!! \n");
		return 0;
	}
	printf("计算出的滤波器的最低阶数 N:  %d , 3分贝截止频率为:%lf\n", *N, *wc);
	printf("--------------------------------------------------------\n");
	
	// 得到 H(s) 的分母
	Linklist* hs_den_list = (Linklist*)malloc(sizeof(Linklist));
	hs_den_list->head = NULL;

	// 获取 hs 的极点 p0 , p1, p2, ... , pn
	// 比如:
	//系数:-0.765367  1.847759 
	//系数: - 1.847759  0.765367
	//系数: - 1.847759 - 0.765367
	//系数: - 0.765367 - 1.847759
	// 极点的系数存储在 hs_den_list
	ret = Butter(*N,
				*wc,
				hs_den_list);
	if (ret == false)
	{
    
    
		printf("error: Butter 执行失败!!!\n");
	}

	// H(s) 的分子的系数为 (wc)^N
	double hs_mol_coeff = pow(*wc, *N);
	printf("hs_mol_coeff = %lf\n", hs_mol_coeff);

	// 将极点转变成 (s-p1), (s-p2),...,(s-pn) 的形式
	// elment_list 中的每一个链表都存放两个Node, 第一个 Node 存放 s, 第二个 Node 存放 p,
	Linklist** elment_list = (Linklist**)malloc(sizeof(Linklist));
	for (int i = 0; i < *N; i++)
	{
    
    
		elment_list[i] = (Linklist*)malloc(sizeof(Linklist));
		elment_list[i]->head = NULL;
	}
	ret = createElementList(*N, hs_den_list, elment_list);
	if (ret == -1)
	{
    
    
		printf("error: createElementList \n");
		return 0;
	}

	// 将 (s-p1), (s-p2),...,(s-pn) 乘起来,结果存放在 mul_list
	Linklist* mul_list = (Linklist*)malloc(sizeof(Linklist));
	mul_list = (Linklist*)malloc(sizeof(Linklist));
	mul_list->head = NULL;
	
	ret = mul_element(*N, elment_list, mul_list);
	if (ret == -1)
	{
    
    
		printf("error: mul_element 失败!!!\n");
		return 0;
	}

	Node* node = mul_list->head;
	printf("========================================\n");
	printf("(s-p1)*(s-p2)*...*(s-pn)的结果 \n");
	while (node != NULL)
	{
    
    
		printf("系数:%lf  %lf , 指数:%d \n", node->coeff->real, node->coeff->img, node->pow);
		node = node->next;
	}

	// 将 H(s) 转换成 H(z),得到 H(z) 的分子和分母,分子存储在 hz_mol_list,分母存储在 hz_den_list
	Linklist* hz_den_list = (Linklist*)malloc(sizeof(Linklist));
	hz_den_list->head = NULL;
	Linklist* hz_mol_list = (Linklist*)malloc(sizeof(Linklist));
	hz_mol_list->head = NULL;
	ret = Bilinear(*N,
		hs_mol_coeff,
		mul_list,
		hz_den_list,
		hz_mol_list,
		IIR_Filter.fs);

	printf("H(z) 的分子:\n");
	node = hz_mol_list->head;
	while (node != NULL)
	{
    
    
		printf("系数:%.15lf  %.15lf , 指数:%d \n", node->coeff->real, node->coeff->img, node->pow);
		node = node->next;
	}
	printf("H(z) 的分母:\n");
	node = hz_den_list->head;
	while (node != NULL)
	{
    
    
		printf("系数:%.15lf  %.15lf , 指数:%d \n", node->coeff->real, node->coeff->img, node->pow);
		node = node->next;
	}

	destoryList(hs_den_list);
	destoryList(hz_den_list);
	destoryList(hz_mol_list);
	printf("Finish \n");
	return (int)0;
}

结果:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Redmoon955331/article/details/129815277