C language implementation of Butterworth low-pass filter

The implementation formula and ideas of C language in this article are referenced from: Digital Signal Processing | Matlab Design Butterworth Low-Pass Filter (Impulse Response Invariant Method and Bilinear Transformation Method),
as well as Professor Chen Houjin of Beijing Jiaotong University and Wan Yong of East China University of Science and Technology Professor Jing's online class


Design a digital Butterworth low-pass filter, the design indicators are as follows:
cut-off frequency of the pass band is 200 Hz,
cut-off frequency of the stop band is 400 Hz,
the maximum attenuation of the pass band is 1 db,
the minimum attenuation of the stop band is 30 db, and
the sampling frequency is 1000 Hz

I have used 3 methods to achieve, two are realized with the help of matlab, and the last one is realized completely using c language. The results obtained by the three methods are the same. My C language implementation can give any index to get the same result as matlab result.
I use C language to realize the buttord and bilinear functions of matlab, buttap function is not realized in the form of function, zp2tf function and lp2lp function are implemented together.
At present, the C language version is only implemented sloppily. It mainly realizes the functions, and the release of memory is very messy and random. I will write a few more articles later to implement each function of matlab in C++ alone, because C language needs to construct its own data structure and troublesome memory management, so it is not suitable for writing these codes.

matlab code implementation

method one:

code:

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(相位)');

result:

insert image description here

Method Two:

code:

%数字低通滤波器指标
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))));

result:

insert image description here

The results obtained by method 1 and method 2 are the same

fdatool implementation

amplitude frequency response

insert image description here

phase frequency response

insert image description here

Numerator and denominator coefficients of H(z)

insert image description here

C language implementation

code:

#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;
}

result:

insert image description here

Guess you like

Origin blog.csdn.net/Redmoon955331/article/details/129815277