├── 4-4-4.mat ├── Bcolors.py ├── Multichannel_FxLMS_algorithm.py ├── Noise_generation.mat ├── Norimalized_Multichannel_FxLMS_algorithm.py ├── Path_generation.mat ├── Pre_training_control_filter_C15_MCANC_AG.py ├── Pre_training_control_filter_C15_Normalaized_MCANC_AG.py ├── Read_tdms.py ├── TdmsWriting_tst.py ├── Tst_4_channel_ANC_program_McFxLMS.py ├── Tst_4_channel_ANC_program_McFxLMS_from_tdms.py ├── Tst_4channel_ANC_program.py ├── Tst_4channel_program.mat └── Tst_4channel_program_McFxLMS.mat /4-4-4.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShiDongyuan/Multichannel_FxLMS_python_code/0851cb2962de89da45d7df587839c1e19255c9dd/4-4-4.mat -------------------------------------------------------------------------------- /Bcolors.py: -------------------------------------------------------------------------------- 1 | class bcolors: 2 | HEADER = '\033[95m' 3 | OKBLUE = '\033[94m' 4 | OKCYAN = '\033[96m' 5 | OKGREEN = '\033[92m' 6 | WARNING = '\033[93m' 7 | FAIL = '\033[91m' 8 | ENDC = '\033[0m' 9 | BOLD = '\033[1m' 10 | UNDERLINE = '\033[4m' -------------------------------------------------------------------------------- /Multichannel_FxLMS_algorithm.py: -------------------------------------------------------------------------------- 1 | # __ __ _____ _ __ __ ____ 2 | # | \/ | ___| ___|_ __| | | \/ |/ ___| 3 | # | |\/| |/ __| |_ \ \/ /| | | |\/| |\___ \ 4 | # | | | | (__| _| > < | |___| | | | ___) | 5 | # |_| |_|\___|_| /_/\_\|_____|_| |_||____/ 6 | #------------------------------------------------------------ 7 | import torch 8 | import numpy as np 9 | import torch.nn as nn 10 | import torch.optim as optim 11 | import scipy.signal as signal 12 | import progressbar 13 | from Bcolors import bcolors 14 | 15 | from rich.console import Console 16 | from rich.table import Column, Table 17 | from rich.progress import track 18 | 19 | #------------------------------------------------------------ 20 | # Class McFxLMS algorithm 21 | #------------------------------------------------------------ 22 | class McFxLMS_algorithm(): 23 | 24 | def __init__(self, R_num, S_num, Len, Sec, device): 25 | ''' 26 | Parameters: 27 | param1 - R_num : the number of the reference microphones. 28 | param2 - S_num : the number of the secondary source. 29 | param3 - Len : the length of the control filter. 30 | param4 - Sec : the secondary path matrix [S_num x E_num x Ls]. 31 | param5 - device: 'GPU' or 'CPUD' 32 | ''' 33 | self.Wc = torch.zeros(R_num, S_num, Len, requires_grad=True, dtype=torch.float, device=device) 34 | self.Xd = torch.zeros(R_num, Len, dtype=torch.float, device=device) 35 | self.Xdm = torch.zeros(Sec.shape[2], R_num, Len, device=device) # [Ls x R_num x Len] 36 | self.Sec = Sec.to(device) 37 | #----------------------------# 38 | # the number of configuration 39 | #----------------------------# 40 | self.r_num = R_num 41 | self.s_num = S_num 42 | self.e_num = Sec.shape[1] 43 | self.len = Len 44 | self.ls = Sec.shape[2] 45 | 46 | self.Yd = torch.zeros(S_num, self.ls, device=device) 47 | #------------------------------------------------------# 48 | # print("<<---------------------------------------------------------------------->>") 49 | # print(bcolors.OKCYAN + f'Reference Num: {self.r_num}, Secondary source Num: {self.s_num}, Error sensors Num: {self.e_num}'+ bcolors.ENDC) 50 | # print(bcolors.OKCYAN + f'The length of control filter is {self.len}, Dimension of Wc is [{self.r_num} x {self.s_num}]'+ bcolors.ENDC) 51 | # print(bcolors.OKCYAN + f'The length of the secondary path is {self.ls}' + bcolors.ENDC) 52 | # print("<<---------------------------------------------------------------------->>") 53 | 54 | console = Console() 55 | table = Table(show_header=True, header_style="bold magenta") 56 | table.add_column("Layers", style="dim", width=12,justify='center') 57 | table.add_column(f'[{self.r_num}x{self.s_num}x{self.e_num}] McFxLMS algorithm', justify="left") 58 | table.add_column("Dimension", justify="left") 59 | table.add_column("Elements", justify="left") 60 | table.add_column("Weights", justify="left") 61 | 62 | table.add_row( 63 | "-1-", 64 | "Control filter", 65 | f'[{self.r_num} x {self.s_num} x {self.len}]', 66 | f'{self.r_num*self.s_num}', 67 | f'{self.r_num*self.s_num*self.len}' 68 | ) 69 | table.add_row( 70 | "-2-", 71 | "Secondary path estimate", 72 | f'[{self.s_num} x {self.e_num} x {self.ls}]', 73 | f'{self.e_num*self.s_num}', 74 | f'{self.s_num*self.e_num*self.ls}' 75 | ) 76 | 77 | console.print(table) 78 | 79 | def feedforward(self, xin): 80 | ''' 81 | Parameter: 82 | param1 - xin : the reference signal [R_num x 1] 83 | param2 - Dis : the disturbance signal [E_num] 84 | ''' 85 | # Shifting the input delay line 86 | self.Xd = torch.roll(self.Xd,1,1) 87 | self.Xd[:,0] = xin 88 | # Shifting the input delay matrix 89 | self.Xdm = torch.roll(self.Xdm,1,0) # [Ls x R_num x Len] 90 | self.Xdm[0,:,:] = self.Xd 91 | # ----------Computational Graph route 1 ------------------------------- 92 | # Building the control singal >>--y_mac--<< 93 | Xd_e = self.Xd.unsqueeze(1) # [R_num x 1 x Len] 94 | y_mac = torch.einsum('rsl,rsl->rs',Xd_e,self.Wc) # [R_num x S_num]---> Filtering the reference signal via different control fitlers 95 | y_out = torch.einsum('rs->s',y_mac) # [S_num] ----> Sum the control sigal from different microphone. 96 | # Cutting the computational chain 97 | y_out_NAG = y_out.detach() 98 | self.Yd = torch.roll(self.Yd,1,1) 99 | self.Yd[:,0] = y_out_NAG 100 | # Generating the control signal 101 | Yd_e = self.Yd.unsqueeze(1) # [S_num x 1 x Ls] 102 | y_anti_mac = torch.einsum('sel,sel->se', Yd_e, self.Sec) # [S_num x E_num] ---> Filtering the control signal. 103 | y_anti = torch.einsum('se->e',y_anti_mac) #[E_num] --> sun the anti-noise from different speakers. 104 | # e = Dis - y_anti 105 | # ----------Computational Graph route 2 ------------------------------- 106 | # Buiding the control signal under the assumpation that all control 107 | # filters are same at Ls time. 108 | Xdm_e = self.Xdm.unsqueeze(2) # [Ls x R_num x 1 x Len] 109 | Wc_e = self.Wc.unsqueeze(0) # [1 x R_num x S_num x Len] 110 | y_e_mac = torch.einsum('nrsl,nrsl->nrs',Xdm_e,Wc_e) # [Ls x R_num x S_num] 111 | y_e_out = torch.einsum('nrs->ns',y_e_mac) # [Ls x S_num] 112 | # Generating the control signal 113 | Yd_e_AG = y_e_out.unsqueeze(1) # [Ls x 1 x S_num] 114 | Yd_e_AG = torch.permute(Yd_e_AG,(2,1,0)) # [S_num x E_num x Ls] 115 | y_anti_mac_AG = torch.einsum('sel,sel->se',Yd_e_AG, self.Sec) 116 | y_anti_AG = torch.einsum('se->e',y_anti_mac_AG) 117 | # E_estimate = Dis - y_anti_AG 118 | 119 | return y_anti_AG, y_anti 120 | 121 | def LossFunction(self, y_anti_AG, y_anti, Dis): 122 | ''' 123 | Parameter: 124 | param1 - y_anti_AG : the anti-nose signal [E_num] with auto gradient 125 | param2 - y_anti : the anti-noise signal 126 | param3 - Dis : the disturbance signal [E_num] 127 | ''' 128 | e = Dis - y_anti 129 | E_estimate = Dis - y_anti_AG 130 | loss = torch.sum(2*torch.einsum('e,e->e', e, E_estimate)) 131 | return loss, e 132 | 133 | def _get_coeff_(self): 134 | return self.Wc.cpu().detach().numpy() 135 | 136 | #------------------------------------------------------------------------------ 137 | # Function : train_fxlms_algorithm() 0.00000005 138 | #------------------------------------------------------------------------------ 139 | def train_fxmclms_algorithm(Model, Ref, Disturbance, device, Stepsize = 0.00000005): 140 | ''' 141 | Parameter: 142 | param1 - Model : the instance of the multichannel FxLMS algorithm. 143 | param2 - Ref : the reference signal vector [R_num x T] 144 | R_num-- the number of the reference microphones. T -- the time index. 145 | param3 - Disturbance : the distrubance vector [E_num x T]. 146 | param4 - Stepsize : the value of the step size. 147 | ''' 148 | #-------------------------------------------- 149 | # if torch.cuda.is_available(): 150 | # device = "cuda" 151 | # else: 152 | # device = "cpu" 153 | print(bcolors.OKCYAN + f"Using {device} for training the McFxLMS algorithm !!!" + bcolors.ENDC) 154 | #-------------------------------------------- 155 | 156 | print(bcolors.WARNING + "<<-------------------------------START---------------------------------->>" + bcolors.ENDC) 157 | print(f'The length of the data is {Disturbance.shape[1]}.') 158 | 159 | #Stepsize = 0.00000005 160 | optimizer= optim.SGD([Model.Wc], lr=Stepsize) 161 | 162 | # bar.start() 163 | Erro_signal = [] 164 | len_data = Disturbance.shape[1] 165 | Ref = Ref.to(device) 166 | Disturbance = Disturbance.to(device) 167 | for itera in track(range(len_data),description="Processing..."): 168 | # Feedfoward 169 | xin = Ref[:,itera] 170 | dis = Disturbance[:,itera] 171 | y_anti_AG, y_anti = Model.feedforward(xin) 172 | loss,e = Model.LossFunction(y_anti_AG, y_anti, dis) 173 | 174 | # Backward 175 | optimizer.zero_grad() 176 | loss.backward() 177 | optimizer.step() 178 | Erro_signal.append(e.cpu().numpy()) 179 | 180 | print(bcolors.WARNING + "<<-------------------------------END------------------------------------>>" + bcolors.ENDC) 181 | return Erro_signal 182 | #------------------------------------------------------------ 183 | # Function : Generating the testing bordband noise 184 | #------------------------------------------------------------ 185 | def Generating_boardband_noise_wavefrom_tensor(Wc_F, Seconds, fs): 186 | filter_len = 1024 187 | bandpass_filter = signal.firwin(filter_len, Wc_F, pass_zero='bandpass', window ='hamming',fs=fs) 188 | N = filter_len + Seconds*fs 189 | xin = np.random.randn(N) 190 | y = signal.lfilter(bandpass_filter,1,xin) 191 | yout= y[filter_len:] 192 | # Standarlize 193 | yout = yout/np.sqrt(np.var(yout)) 194 | # return a tensor of [1 x sample rate] 195 | return torch.from_numpy(yout).type(torch.float).unsqueeze(0) 196 | 197 | #------------------------------------------------------------ 198 | # Function : Generating the testing bordband noise 199 | #------------------------------------------------------------ 200 | def Generating_boardband_noise_wavefrom_tensor(Wc_F, Seconds, fs): 201 | filter_len = 1024 202 | bandpass_filter = signal.firwin(filter_len, Wc_F, pass_zero='bandpass', window ='hamming',fs=fs) 203 | N = filter_len + Seconds*fs 204 | xin = np.random.randn(N) 205 | y = signal.lfilter(bandpass_filter,1,xin) 206 | yout= y[filter_len:] 207 | # Standarlize 208 | yout = yout/np.sqrt(np.var(yout)) 209 | # return a tensor of [1 x sample rate] 210 | return torch.from_numpy(yout).type(torch.float).unsqueeze(0) 211 | 212 | #------------------------------------------------------------- 213 | # Function : Disturbance_reference_generation_from_Fvector() 214 | # Discription : Generating the distubrane and reference signal from the defined parameters 215 | #------------------------------------------------------------- 216 | def Disturbance_Noise_generation_from_Fvector(fs, T, f_vector, Pri_path, Sec_path): 217 | """ 218 | Pri_path and Sec_path are One dimension arraies 219 | """ 220 | # ANC platform configuration 221 | t = np.arange(0,T,1/fs).reshape(-1,1) 222 | len_f = 1024 223 | b2 = signal.firwin(len_f, [f_vector[0],f_vector[1]], pass_zero='bandpass', window ='hamming',fs=fs) 224 | xin = np.random.randn(len(t)) 225 | Re = signal.lfilter(b2,1,xin) 226 | Noise = Re[len_f-1:] 227 | # Noise = Noise/np.sqrt(np.var(Noise)) 228 | 229 | # Construting the desired signal 230 | Dir, Fx = signal.lfilter(Pri_path, 1, Noise), signal.lfilter(Sec_path, 1, Noise) 231 | 232 | return torch.from_numpy(Dir).type(torch.float), torch.from_numpy(Noise).type(torch.float) 233 | 234 | #------------------------------------------------------------------- -------------------------------------------------------------------------------- /Noise_generation.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShiDongyuan/Multichannel_FxLMS_python_code/0851cb2962de89da45d7df587839c1e19255c9dd/Noise_generation.mat -------------------------------------------------------------------------------- /Norimalized_Multichannel_FxLMS_algorithm.py: -------------------------------------------------------------------------------- 1 | # __ __ _____ _ _ _ __ __ ____ 2 | # | \/ | ___| ___|_ __| \ | | | | \/ |/ ___| 3 | # | |\/| |/ __| |_ \ \/ /| \| | | | |\/| |\___ \ 4 | # | | | | (__| _| > < | |\ | |___| | | | ___) | 5 | # |_| |_|\___|_| /_/\_\|_| \_|_____|_| |_||____/ 6 | #------------------------------------------------------------ 7 | import torch 8 | import numpy as np 9 | import torch.nn as nn 10 | import torch.optim as optim 11 | import scipy.signal as signal 12 | 13 | from Bcolors import bcolors 14 | from rich.console import Console 15 | from rich.table import Column, Table 16 | from rich.progress import track 17 | 18 | #------------------------------------------------------------ 19 | # Class : Normalized McFxLMS algorithm 20 | # This is a Normalzed McFxLMS algorithm class. 21 | #------------------------------------------------------------ 22 | class McFxNLMS_algorithm(): 23 | 24 | def __init__(self, R_num, S_num, Len, Sec, device): 25 | ''' 26 | Parameters: 27 | param1 - R_num : the number of the reference microphones. 28 | param2 - S_num : the number of the secondary source. 29 | param3 - Len : the length of the control filter. 30 | param4 - Sec : the secondary path matrix [S_num x E_num x Ls]. 31 | ''' 32 | self.Wc = torch.zeros(R_num, S_num, Len, requires_grad=True, dtype=torch.float, device=device) 33 | self.Xd = torch.zeros(R_num, Len, dtype=torch.float, device=device) 34 | self.Xf = torch.zeros(R_num, Sec.shape[2], dtype=torch.float, device=device) # [R_num x Ls] delay line for filterd reference. 35 | self.Xdm = torch.zeros(Sec.shape[2], R_num, Len, device=device) # [Ls x R_num x Len] 36 | self.Xfm = torch.zeros(Len, R_num, Sec.shape[2], device=device) # [Len x R_num, Ls] 37 | self.Sec = Sec.to(device) 38 | #----------------------------# 39 | # the number of configuration 40 | #----------------------------# 41 | self.r_num = R_num 42 | self.s_num = S_num 43 | self.e_num = Sec.shape[1] 44 | self.len = Len 45 | self.ls = Sec.shape[2] 46 | 47 | self.Yd = torch.zeros(S_num, self.ls, device=device) 48 | #----------------------------# 49 | # Print the object information 50 | #----------------------------# 51 | console = Console() 52 | table = Table(show_header=True, header_style="bold magenta") 53 | table.add_column("Layers", style="dim", width=12,justify='center') 54 | table.add_column(f'[{self.r_num}x{self.s_num}x{self.e_num}] McFxNLMS algorithm', justify="left") 55 | table.add_column("Dimension", justify="left") 56 | table.add_column("Elements", justify="left") 57 | table.add_column("Weights", justify="left") 58 | 59 | table.add_row( 60 | "-1-", 61 | "Control filter", 62 | f'[{self.r_num} x {self.s_num} x {self.len}]', 63 | f'{self.r_num*self.s_num}', 64 | f'{self.r_num*self.s_num*self.len}' 65 | ) 66 | table.add_row( 67 | "-2-", 68 | "Secondary path estimate", 69 | f'[{self.s_num} x {self.e_num} x {self.ls}]', 70 | f'{self.e_num*self.s_num}', 71 | f'{self.s_num*self.e_num*self.ls}' 72 | ) 73 | 74 | console.print(table) 75 | 76 | def feedforward(self, xin): 77 | ''' 78 | Parameter: 79 | param1 - xin : the reference signal [R_num x 1] 80 | param2 - Dis : the disturbance signal [E_num] 81 | ''' 82 | # Shifting the input delay line 83 | self.Xd = torch.roll(self.Xd,1,1) 84 | self.Xd[:,0] = xin 85 | # Shifting the input delay matrix 86 | self.Xdm = torch.roll(self.Xdm,1,0) # [Ls x R_num x Len] 87 | self.Xdm[0,:,:] = self.Xd 88 | 89 | # Shifting the input for calculating the filtered input power 90 | self.Xf = torch.roll(self.Xf,1,1) 91 | self.Xf[:,0] = xin 92 | self.Xfm = torch.roll(self.Xfm,1,0) # [[Len x R_num x Ls]] 93 | self.Xfm[0,:,:] = self.Xf 94 | 95 | xf_n = torch.permute(self.Xfm,(1,0,2)) # [R_num x Len x Ls] 96 | X_rsenl = xf_n.unsqueeze(1).unsqueeze(1) # [R_num x 1 x 1 x Len x Ls] 97 | Sec_rsenl = self.Sec.unsqueeze(0).unsqueeze(3) #[1 x S_num x E_num x 1 x Ls] 98 | Xf_rsen = torch.einsum('resnl,resnl->resn',X_rsenl, Sec_rsenl) 99 | Xp_rse = torch.einsum('rsen, rsen->rse',Xf_rsen,Xf_rsen) 100 | #Xp_e = torch.einsum('rse->e',Xp_rse) + torch.tensor(1e-12, dtype=torch.float) 101 | Xp_e = torch.einsum('rse->e',Xp_rse) 102 | Xp_e = Xp_e.masked_fill_(Xp_e==0, float(-1e20)) 103 | 104 | # ----------Computational Graph route 1 ------------------------------- 105 | # Building the control singal >>--y_mac--<< 106 | Xd_e = self.Xd.unsqueeze(1) # [R_num x 1 x Len] 107 | y_mac = torch.einsum('rsl,rsl->rs',Xd_e,self.Wc) # [R_num x S_num]---> Filtering the reference signal via different control fitlers 108 | y_out = torch.einsum('rs->s',y_mac) # [S_num] ----> Sum the control sigal from different microphone. 109 | # Cutting the computational chain 110 | y_out_NAG = y_out.detach() 111 | self.Yd = torch.roll(self.Yd,1,1) 112 | self.Yd[:,0] = y_out_NAG 113 | # Generating the control signal 114 | Yd_e = self.Yd.unsqueeze(1) # [S_num x 1 x Ls] 115 | y_anti_mac = torch.einsum('sel,sel->se', Yd_e, self.Sec) # [S_num x E_num] ---> Filtering the control signal. 116 | y_anti = torch.einsum('se->e',y_anti_mac) #[E_num] --> sun the anti-noise from different speakers. 117 | # e = Dis - y_anti 118 | # ----------Computational Graph route 2 ------------------------------- 119 | # Buiding the control signal under the assumpation that all control 120 | # filters are same at Ls time. 121 | Xdm_e = self.Xdm.unsqueeze(2) # [Ls x R_num x 1 x Len] 122 | Wc_e = self.Wc.unsqueeze(0) # [1 x R_num x S_num x Len] 123 | y_e_mac = torch.einsum('nrsl,nrsl->nrs',Xdm_e,Wc_e) # [Ls x R_num x S_num] 124 | y_e_out = torch.einsum('nrs->ns',y_e_mac) # [Ls x S_num] 125 | # Generating the control signal 126 | Yd_e_AG = y_e_out.unsqueeze(1) # [Ls x 1 x S_num] 127 | Yd_e_AG = torch.permute(Yd_e_AG,(2,1,0)) # [S_num x E_num x Ls] 128 | y_anti_mac_AG = torch.einsum('sel,sel->se',Yd_e_AG, self.Sec) 129 | y_anti_AG = torch.einsum('se->e',y_anti_mac_AG) 130 | # E_estimate = Dis - y_anti_AG 131 | 132 | return y_anti_AG, y_anti, Xp_e 133 | 134 | def LossFunction(self, y_anti_AG, y_anti, Dis, Xp_e): 135 | ''' 136 | Parameter: 137 | param1 - y_anti_AG : the anti-nose signal [E_num] with auto gradient 138 | param2 - y_anti : the anti-noise signal 139 | param3 - Dis : the disturbance signal [E_num] 140 | ''' 141 | e = Dis - y_anti 142 | E_estimate = Dis - y_anti_AG 143 | loss = torch.sum(torch.einsum('e,e->e',2*torch.einsum('e,e->e', e, E_estimate),1/Xp_e)) 144 | return loss, e 145 | 146 | def _get_coeff_(self): 147 | return self.Wc.cpu().detach().numpy() 148 | 149 | #------------------------------------------------------------------------------ 150 | # Function : train_McFxNLMS_algorithm() 0.00000005 151 | # This function is used to train the the normalized McFxLMS algorithm. 152 | #------------------------------------------------------------------------------ 153 | def train_McFxNLMS_algorithm(Model, Ref, Disturbance, device, Stepsize = 0.01): 154 | ''' 155 | Parameter: 156 | param1 - Model : the instance of the multichannel FxLMS algorithm. 157 | param2 - Ref : the reference signal vector [R_num x T] 158 | R_num-- the number of the reference microphones. T -- the time index. 159 | param3 - Disturbance : the distrubance vector [E_num x T]. 160 | param4 - Stepsize : the value of the step size. 161 | ''' 162 | #-------------------------------------------- 163 | # if torch.cuda.is_available(): 164 | # device = "cuda" 165 | # else: 166 | # device = "cpu" 167 | print(bcolors.WARNING + f"Using {device} for training the McFxLMS algorithm !!!" + bcolors.ENDC) 168 | #-------------------------------------------- 169 | 170 | print(bcolors.WARNING + "<<-------------------------------START---------------------------------->>" + bcolors.ENDC) 171 | print(f'The length of the data is {Disturbance.shape[1]}.') 172 | 173 | #Stepsize = 0.00000005 174 | optimizer= optim.SGD([Model.Wc], lr=Stepsize) 175 | 176 | # bar.start() 177 | Erro_signal = [] 178 | len_data = Disturbance.shape[1] 179 | Ref = Ref.to(device) 180 | Disturbance = Disturbance.to(device) 181 | for itera in track(range(len_data),description="Processing..."): 182 | # Feedfoward 183 | xin = Ref[:,itera] 184 | dis = Disturbance[:,itera] 185 | y_anti_AG, y_anti, Xp_e = Model.feedforward(xin) 186 | loss,e = Model.LossFunction(y_anti_AG, y_anti, dis, Xp_e) 187 | 188 | # Backward 189 | optimizer.zero_grad() 190 | loss.backward() 191 | optimizer.step() 192 | Erro_signal.append(e.cpu().numpy()) 193 | 194 | print(bcolors.WARNING + "<<-------------------------------END------------------------------------>>" + bcolors.ENDC) 195 | return Erro_signal 196 | 197 | #------------------------------------------------------------ 198 | # Function : Generating the testing bordband noise 199 | #------------------------------------------------------------ 200 | def Generating_boardband_noise_wavefrom_tensor(Wc_F, Seconds, fs): 201 | filter_len = 1024 202 | bandpass_filter = signal.firwin(filter_len, Wc_F, pass_zero='bandpass', window ='hamming',fs=fs) 203 | N = filter_len + Seconds*fs 204 | xin = np.random.randn(N) 205 | y = signal.lfilter(bandpass_filter,1,xin) 206 | yout= y[filter_len:] 207 | # Standarlize 208 | yout = yout/np.sqrt(np.var(yout)) 209 | # return a tensor of [1 x sample rate] 210 | return torch.from_numpy(yout).type(torch.float).unsqueeze(0) 211 | 212 | #------------------------------------------------------------ 213 | # Function : Generating the testing bordband noise 214 | #------------------------------------------------------------ 215 | def Generating_boardband_noise_wavefrom_tensor(Wc_F, Seconds, fs): 216 | filter_len = 1024 217 | bandpass_filter = signal.firwin(filter_len, Wc_F, pass_zero='bandpass', window ='hamming',fs=fs) 218 | N = filter_len + Seconds*fs 219 | xin = np.random.randn(N) 220 | y = signal.lfilter(bandpass_filter,1,xin) 221 | yout= y[filter_len:] 222 | # Standarlize 223 | yout = yout/np.sqrt(np.var(yout)) 224 | # return a tensor of [1 x sample rate] 225 | return torch.from_numpy(yout).type(torch.float).unsqueeze(0) 226 | 227 | #------------------------------------------------------------- 228 | # Function : Disturbance_reference_generation_from_Fvector() 229 | # Discription : Generating the distubrane and reference signal from the defined parameters 230 | #------------------------------------------------------------- 231 | def Disturbance_Noise_generation_from_Fvector(fs, T, f_vector, Pri_path, Sec_path): 232 | """ 233 | Pri_path and Sec_path are One dimension arraies 234 | """ 235 | # ANC platform configuration 236 | t = np.arange(0,T,1/fs).reshape(-1,1) 237 | len_f = 1024 238 | b2 = signal.firwin(len_f, [f_vector[0],f_vector[1]], pass_zero='bandpass', window ='hamming',fs=fs) 239 | xin = np.random.randn(len(t)) 240 | Re = signal.lfilter(b2,1,xin) 241 | Noise = Re[len_f-1:] 242 | # Noise = Noise/np.sqrt(np.var(Noise)) 243 | 244 | # Construting the desired signal 245 | Dir, Fx = signal.lfilter(Pri_path, 1, Noise), signal.lfilter(Sec_path, 1, Noise) 246 | 247 | return torch.from_numpy(Dir).type(torch.float), torch.from_numpy(Noise).type(torch.float) 248 | 249 | #------------------------------------------------------------------- -------------------------------------------------------------------------------- /Path_generation.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShiDongyuan/Multichannel_FxLMS_python_code/0851cb2962de89da45d7df587839c1e19255c9dd/Path_generation.mat -------------------------------------------------------------------------------- /Pre_training_control_filter_C15_MCANC_AG.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import torch 4 | import matplotlib.pyplot as plt 5 | import scipy.io as sio 6 | from Multichannel_FxLMS_algorithm import McFxLMS_algorithm, train_fxmclms_algorithm, Disturbance_Noise_generation_from_Fvector 7 | from scipy.io import savemat 8 | from scipy import signal 9 | 10 | #----------------------------------------------------------------------------------- 11 | # Function: save_mat__() 12 | # Description: Save the data into mat file for 13 | # Matlab. 14 | #----------------------------------------------------------------------------------- 15 | def save_mat__(FILE_NAME_PATH, Wc): 16 | mdict= {'Wc_v': Wc} 17 | savemat(FILE_NAME_PATH, mdict) 18 | 19 | #----------------------------------------------------------------------------------- 20 | # Function loading_paths_from_MAT() 21 | #----------------------------------------------------------------------------------- 22 | def loading_paths_from_MAT(folder = 'Duct_path' 23 | ,Pri_path_file_name = 'Primary_path.mat' 24 | ,Sec_path_file_name ='Secondary_path.mat'): 25 | Primay_path_file, Secondary_path_file = os.path.join(folder, Pri_path_file_name), os.path.join(folder,Sec_path_file_name) 26 | Pri_dfs, Secon_dfs = sio.loadmat(Primay_path_file), sio.loadmat(Secondary_path_file) 27 | Pri_path, Secon_path = Pri_dfs['Pri_path'].squeeze(), Secon_dfs['Sec_path'].squeeze() 28 | return Pri_path, Secon_path 29 | 30 | #----------------------------------------------------------------------------------- 31 | # Class : frequencyband_design() 32 | # Description : The function is utilized to devide the full frequency band into 33 | # several equal frequency components. 34 | #----------------------------------------------------------------------------------- 35 | def frequencyband_design(level,fs): 36 | # the number of filter equals 2^level. 37 | # fs represents the sampling rate. 38 | Num = 2**level 39 | # Computing the start and end of the frequency band. 40 | #---------------------------------------------------- 41 | F_vector = [] 42 | f_start = 20 43 | f_marge = 20 44 | # the wideth of thefrequency band 45 | width = (fs/2-f_start-f_marge)//Num 46 | #---------------------------------------------------- 47 | for ii in range(Num): 48 | f_end = f_start + width 49 | F_vector.append([f_start,f_end]) 50 | f_start = f_end 51 | #---------------------------------------------------- 52 | return F_vector, width 53 | 54 | #----------------------------------------------------------------------------------- 55 | def main(): 56 | FILE_NAME_PATH = 'Control_filter_from_15frequencies.mat' 57 | # Configurating the system parameters 58 | fs = 16000 59 | T = 30 60 | Len_control = 1024 61 | level = 4 #4 62 | 63 | Frequecy_band = [] 64 | for i in range(level): 65 | F_vec, _ = frequencyband_design(i, fs) 66 | Frequecy_band += F_vec 67 | 68 | # Loading the primary and secondary path 69 | # Pri_path, Secon_path = loading_paths() 70 | Pri_path, Secon_path = loading_paths_from_MAT() 71 | Sec = torch.from_numpy(Secon_path).type(torch.float).unsqueeze(0) 72 | 73 | # Training the control filters from the defined frequency band 74 | num_filters = len(Frequecy_band) 75 | Wc_matrix = np.zeros((num_filters, Len_control), dtype=float) 76 | 77 | print(Frequecy_band) 78 | 79 | 80 | for ii, F_vector in enumerate( Frequecy_band): 81 | print(F_vector) 82 | Dis, Re = Disturbance_Noise_generation_from_Fvector(fs=fs, T= T, f_vector=F_vector, Pri_path=Pri_path, Sec_path=Secon_path) 83 | #controller = FxLMS_AG_algroithm(Len=Len_control,) 84 | #---------------------------- 85 | Re2 = torch.cat((Re.unsqueeze(0),Re.unsqueeze(0)),0) 86 | Dis2 = torch.cat((Dis.unsqueeze(0),Dis.unsqueeze(0)),0) 87 | SecM2 = torch.zeros(2,2,len(Sec)) 88 | SecM2 = SecM2 + Sec.unsqueeze(0) 89 | print(Re2.shape) 90 | print(SecM2) 91 | #---------------------------- 92 | #-------------------------------------------- 93 | if torch.cuda.is_available(): 94 | device = "cuda" 95 | else: 96 | device = "cpu" 97 | #-------------------------------------------- 98 | controller = McFxLMS_algorithm(R_num=2, S_num=2, Len=Len_control, Sec=SecM2, device=device) 99 | 100 | Erro = train_fxmclms_algorithm(Model=controller, Ref=Re2, Disturbance=Dis2, device=device, Stepsize=0.00001) 101 | Wc_matrix[ii] = controller._get_coeff_()[0,0,:] 102 | 103 | Err_array = np.array(Erro) 104 | # Drawing the impulse response of the primary path 105 | plt.title('The error signal of the FxLMS algorithm') 106 | plt.plot(Err_array[:,0]) 107 | plt.ylabel('Amplitude') 108 | plt.xlabel('Time') 109 | plt.grid() 110 | plt.show() 111 | 112 | fs=16000 113 | f, Pper_spec = signal.periodogram(Wc_matrix[ii] , fs, 'flattop', scaling='spectrum') 114 | plt.semilogy(f, Pper_spec) 115 | plt.xlabel('frequency [Hz]') 116 | plt.ylabel('PSD') 117 | plt.grid() 118 | plt.show() 119 | 120 | save_mat__(FILE_NAME_PATH, Wc_matrix) 121 | 122 | if __name__ == "__main__": 123 | main() -------------------------------------------------------------------------------- /Pre_training_control_filter_C15_Normalaized_MCANC_AG.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import torch 4 | import matplotlib.pyplot as plt 5 | import scipy.io as sio 6 | 7 | from Norimalized_Multichannel_FxLMS_algorithm import McFxNLMS_algorithm, train_McFxNLMS_algorithm, Disturbance_Noise_generation_from_Fvector 8 | from scipy.io import savemat 9 | from scipy import signal 10 | 11 | #----------------------------------------------------------------------------------- 12 | # Function: save_mat__() 13 | # Description: Save the data into mat file for 14 | # Matlab. 15 | #----------------------------------------------------------------------------------- 16 | def save_mat__(FILE_NAME_PATH, Wc): 17 | mdict= {'Wc_v': Wc} 18 | savemat(FILE_NAME_PATH, mdict) 19 | 20 | #----------------------------------------------------------------------------------- 21 | # Function loading_paths_from_MAT() 22 | #----------------------------------------------------------------------------------- 23 | def loading_paths_from_MAT(folder = 'Duct_path' 24 | ,Pri_path_file_name = 'Primary_path.mat' 25 | ,Sec_path_file_name ='Secondary_path.mat'): 26 | Primay_path_file, Secondary_path_file = os.path.join(folder, Pri_path_file_name), os.path.join(folder,Sec_path_file_name) 27 | Pri_dfs, Secon_dfs = sio.loadmat(Primay_path_file), sio.loadmat(Secondary_path_file) 28 | Pri_path, Secon_path = Pri_dfs['Pri_path'].squeeze(), Secon_dfs['Sec_path'].squeeze() 29 | return Pri_path, Secon_path 30 | 31 | #----------------------------------------------------------------------------------- 32 | # Class : frequencyband_design() 33 | # Description : The function is utilized to devide the full frequency band into 34 | # several equal frequency components. 35 | #----------------------------------------------------------------------------------- 36 | def frequencyband_design(level,fs): 37 | # the number of filter equals 2^level. 38 | # fs represents the sampling rate. 39 | Num = 2**level 40 | # Computing the start and end of the frequency band. 41 | #---------------------------------------------------- 42 | F_vector = [] 43 | f_start = 20 44 | f_marge = 20 45 | # the wideth of thefrequency band 46 | width = (fs/2-f_start-f_marge)//Num 47 | #---------------------------------------------------- 48 | for ii in range(Num): 49 | f_end = f_start + width 50 | F_vector.append([f_start,f_end]) 51 | f_start = f_end 52 | #---------------------------------------------------- 53 | return F_vector, width 54 | 55 | #----------------------------------------------------------------------------------- 56 | def main(): 57 | FILE_NAME_PATH = 'Control_filter_from_15frequencies.mat' 58 | # Configurating the system parameters 59 | fs = 16000 60 | T = 30 61 | Len_control = 1024 62 | level = 4 #4 63 | 64 | Frequecy_band = [] 65 | for i in range(level): 66 | F_vec, _ = frequencyband_design(i, fs) 67 | Frequecy_band += F_vec 68 | 69 | # Loading the primary and secondary path 70 | # Pri_path, Secon_path = loading_paths() 71 | Pri_path, Secon_path = loading_paths_from_MAT() 72 | Sec = torch.from_numpy(Secon_path).type(torch.float).unsqueeze(0) 73 | 74 | # Training the control filters from the defined frequency band 75 | num_filters = len(Frequecy_band) 76 | Wc_matrix = np.zeros((num_filters, Len_control), dtype=float) 77 | 78 | print(Frequecy_band) 79 | 80 | 81 | for ii, F_vector in enumerate( Frequecy_band): 82 | print(F_vector) 83 | Dis, Re = Disturbance_Noise_generation_from_Fvector(fs=fs, T= T, f_vector=F_vector, Pri_path=Pri_path, Sec_path=Secon_path) 84 | #controller = FxLMS_AG_algroithm(Len=Len_control,) 85 | #---------------------------- 86 | Re2 = torch.cat((Re.unsqueeze(0),Re.unsqueeze(0)),0) 87 | Dis2 = torch.cat((Dis.unsqueeze(0),Dis.unsqueeze(0)),0) 88 | SecM2 = torch.zeros(2,2,len(Sec)) 89 | SecM2 = SecM2 + Sec.unsqueeze(0) 90 | print(Re2.shape) 91 | print(SecM2) 92 | #-------------------------------------------- 93 | 94 | #-------------------------------------------- 95 | if torch.cuda.is_available(): 96 | device = "cuda" 97 | else: 98 | device = "cpu" 99 | 100 | controller = McFxNLMS_algorithm(R_num=2, S_num=2, Len=Len_control, Sec=SecM2, device=device) 101 | 102 | Erro = train_McFxNLMS_algorithm(Model=controller, Ref=Re2, Disturbance=Dis2, Stepsize=0.01) 103 | Wc_matrix[ii] = controller._get_coeff_()[0,0,:] 104 | 105 | # Drawing the impulse response of the primary path 106 | plt.title('The error signal of the FxLMS algorithm') 107 | plt.plot(Erro) 108 | plt.ylabel('Amplitude') 109 | plt.xlabel('Time') 110 | plt.grid() 111 | plt.show() 112 | 113 | fs=16000 114 | f, Pper_spec = signal.periodogram(Wc_matrix[ii] , fs, 'flattop', scaling='spectrum') 115 | plt.semilogy(f, Pper_spec) 116 | plt.xlabel('frequency [Hz]') 117 | plt.ylabel('PSD') 118 | plt.grid() 119 | plt.show() 120 | 121 | save_mat__(FILE_NAME_PATH, Wc_matrix) 122 | 123 | if __name__ == "__main__": 124 | main() -------------------------------------------------------------------------------- /Read_tdms.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | from nptdms import TdmsFile 4 | 5 | #----------------------------------------------------------------------------------------- 6 | # Class: TDMS_reader 7 | # Description : reading the reference and disturbance signals from TDMS file. 8 | #----------------------------------------------------------------------------------------- 9 | class TDMS_reader: 10 | 11 | def __init__(self, file_name='Reference_Disturbance.tdms', Num_Ref=None, Num_Err=None): 12 | """ Creates a new reader of tdms file. 13 | 14 | :param file_name: The file name of the reading tdms file. 15 | :param Num_Ref : The number of the reference sensors. 16 | :param Num_Err : The number of the error sensors. 17 | """ 18 | self.tdms = TdmsFile.read(file_name) 19 | self.Num_r = Num_Ref 20 | self.Num_e = Num_Err 21 | 22 | def reading_to_tensor(self): 23 | """ Reading the error signal and reference signal to tensor 24 | 25 | Returns: 26 | Refer_vector : The reference signal tensor [Number of reference x T] 27 | Error_vector : The error signal tensor [Number of error x T] 28 | """ 29 | tdms_file = self.tdms 30 | Error_vector = [] 31 | Refer_vector = [] 32 | for group in tdms_file.groups(): 33 | for ii, channel in enumerate(group.channels()): 34 | if ii < self.Num_r : 35 | Refer_vector.append(channel[:]) 36 | else : 37 | Error_vector.append(channel[:]) 38 | 39 | return torch.from_numpy(np.array(Refer_vector)).type(torch.float), torch.from_numpy(np.array(Error_vector)).type(torch.float) 40 | 41 | if __name__=="__main__": 42 | 43 | a = TDMS_reader(Num_Ref=4, Num_Err=4) 44 | refer, error = a.reading_to_tensor() 45 | 46 | print(error.shape) -------------------------------------------------------------------------------- /TdmsWriting_tst.py: -------------------------------------------------------------------------------- 1 | from nptdms import TdmsWriter, ChannelObject 2 | import numpy as np 3 | import torch 4 | from scipy.io import savemat 5 | import scipy.io as sio 6 | 7 | # with TdmsWriter('path_to_file.tdms') as tdms_writer: 8 | # data_array = np.linspace(0,100,100) 9 | # channel = ChannelObject('Group', 'Channel1', data_array) 10 | # channel2 = ChannelObject('Group', 'Channel2', data_array) 11 | # tdms_writer.write_segment([channel, channel2]) 12 | 13 | def TDMS_writting(file_name='path_to_file.tdms', Ref=None, Distur=None): 14 | Num_ref = Ref.shape[1] 15 | Num_err = Distur.shape[1] 16 | 17 | with TdmsWriter(file_name) as tdms_writer: 18 | for ii in range(Num_ref): 19 | channel = ChannelObject('Group',f'Reference_{ii}', Ref[:,ii]) 20 | tdms_writer.write_segment([channel]) 21 | 22 | for jj in range(Num_err): 23 | channel = ChannelObject('Group',f'Disturbance_{jj}', Distur[:,jj]) 24 | tdms_writer.write_segment([channel]) 25 | 26 | # data_array = numpy.expand_dims(numpy.linspace(0,100,100),axis=1) 27 | 28 | # print(data_array.shape) 29 | 30 | # Data_tenosr = torch.tensor(numpy.concatenate((data_array,data_array),axis=1), dtype=float) 31 | # print(Data_tenosr) 32 | 33 | #------------------------------------------------------------ 34 | # Function : Load_noise_path_from_mat() 35 | # Loading primary path and noise from mat. 36 | #------------------------------------------------------------ 37 | def Load_noise_path_from_mat(Noise_mat_file='Noise_generation.mat', Path_mat_file='Path_generation.mat'): 38 | Refer_matrix = torch.from_numpy(sio.loadmat(Noise_mat_file)['Refer_matrix']).type(torch.float) 39 | Distur_matrix = torch.from_numpy(sio.loadmat(Noise_mat_file)['Distur_matrix']).type(torch.float) 40 | Primary_path_matrix = torch.from_numpy(sio.loadmat(Path_mat_file)['Primary_path_matrix']).type(torch.float) 41 | Secondary_path_matrix = torch.from_numpy(sio.loadmat(Path_mat_file)['Secondary_path_matrix']).type(torch.float) 42 | 43 | return Primary_path_matrix, Secondary_path_matrix, Refer_matrix, Distur_matrix 44 | 45 | if __name__== "__main__": 46 | 47 | Pri_mat, Sec_mat, Refer_mat, Distur_mat = Load_noise_path_from_mat() 48 | print(Refer_mat.numpy().shape) 49 | TDMS_writting(file_name='Reference_Disturbance.tdms', Ref=Refer_mat.numpy(), Distur=Distur_mat.numpy()) 50 | pass -------------------------------------------------------------------------------- /Tst_4_channel_ANC_program_McFxLMS.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import torch 4 | import matplotlib.pyplot as plt 5 | import scipy.io as sio 6 | 7 | from Multichannel_FxLMS_algorithm import McFxLMS_algorithm, train_fxmclms_algorithm 8 | from scipy.io import savemat 9 | from scipy import signal 10 | 11 | #------------------------------------------------------------ 12 | # Function : Save_data_to_mat() 13 | #------------------------------------------------------------ 14 | def Save_data_to_mat(Mat_file_name ='Tst_4channel_program.mat', **kwargs): 15 | mdict = {} 16 | for arg in kwargs: 17 | mdict[arg] = kwargs[arg] 18 | savemat(Mat_file_name, mdict) 19 | 20 | #------------------------------------------------------------ 21 | # Function : Load_noise_path_from_mat() 22 | # Loading primary path and noise from mat. 23 | #------------------------------------------------------------ 24 | def Load_noise_path_from_mat(Noise_mat_file='Noise_generation.mat', Path_mat_file='Path_generation.mat'): 25 | Refer_matrix = torch.from_numpy(sio.loadmat(Noise_mat_file)['Refer_matrix']).type(torch.float) 26 | Distur_matrix = torch.from_numpy(sio.loadmat(Noise_mat_file)['Distur_matrix']).type(torch.float) 27 | Primary_path_matrix = torch.from_numpy(sio.loadmat(Path_mat_file)['Primary_path_matrix']).type(torch.float) 28 | Secondary_path_matrix = torch.from_numpy(sio.loadmat(Path_mat_file)['Secondary_path_matrix']).type(torch.float) 29 | 30 | return Primary_path_matrix, Secondary_path_matrix, Refer_matrix, Distur_matrix 31 | 32 | #------------------------------------------------------------ 33 | if __name__ == "__main__": 34 | Pri_mat, Sec_mat, Refer_mat, Distur_mat = Load_noise_path_from_mat() 35 | 36 | Sec_path = torch.permute(Sec_mat,(2,0,1)) 37 | Refer = torch.permute(Refer_mat,(1,0)) 38 | Distu = torch.permute(Distur_mat,(1,0)) 39 | print(Refer.shape) 40 | 41 | #-------------------------------------------- 42 | Len_control = 512 43 | num_filters = 16 44 | #Wc_matrix = np.zeros((num_filters, Len_control), dtype=float) 45 | if torch.cuda.is_available(): 46 | device = "cuda" 47 | else: 48 | device = "cpu" 49 | 50 | controller = McFxLMS_algorithm(R_num=4, S_num=4, Len=Len_control, Sec=Sec_path, device=device) 51 | Erro = train_fxmclms_algorithm(Model=controller, Ref=Refer, Disturbance=Distu, device= device, Stepsize=0.000013) 52 | Wc_matrix = controller._get_coeff_() 53 | 54 | # Saving the mat 55 | Err_array = np.array(Erro) 56 | Save_data_to_mat(Mat_file_name ='Tst_4channel_program_McFxLMS.mat', Wc_matrix=Wc_matrix, Err_array=Err_array) 57 | print(Err_array.shape) 58 | 59 | # Drawing the impulse response of the primary path 60 | plt.title('The error signal of the FxLMS algorithm') 61 | plt.plot(Err_array[:,0]) 62 | plt.ylabel('Amplitude') 63 | plt.xlabel('Time') 64 | plt.grid() 65 | plt.show() 66 | 67 | fs=16000 68 | f, Pper_spec = signal.periodogram(Wc_matrix[0,0,:] , fs, 'flattop', scaling='spectrum') 69 | plt.semilogy(f, Pper_spec) 70 | plt.xlabel('frequency [Hz]') 71 | plt.ylabel('PSD') 72 | plt.grid() 73 | plt.show() 74 | -------------------------------------------------------------------------------- /Tst_4_channel_ANC_program_McFxLMS_from_tdms.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import matplotlib.pyplot as plt 3 | import scipy.io as sio 4 | import numpy as np 5 | 6 | from Multichannel_FxLMS_algorithm import McFxLMS_algorithm, train_fxmclms_algorithm 7 | from scipy.io import savemat 8 | from scipy import signal 9 | from Read_tdms import TDMS_reader 10 | from Tst_4_channel_ANC_program_McFxLMS import Load_noise_path_from_mat 11 | 12 | #------------------------------------------------------------ 13 | # Function : Save_data_to_mat() 14 | #------------------------------------------------------------ 15 | def Save_data_to_mat(Mat_file_name ='Tst_4channel_program.mat', **kwargs): 16 | mdict = {} 17 | for arg in kwargs: 18 | mdict[arg] = kwargs[arg] 19 | savemat(Mat_file_name, mdict) 20 | 21 | if __name__ == "__main__": 22 | a = TDMS_reader(Num_Ref=4, Num_Err=4) 23 | Pri_mat, Sec_mat, Refer_mat, Distur_mat = Load_noise_path_from_mat() 24 | 25 | Sec_path = torch.permute(Sec_mat,(2,0,1)) 26 | Refer, Distu= a.reading_to_tensor() 27 | print(Refer.shape) 28 | 29 | #-------------------------------------------- 30 | Len_control = 512 31 | num_filters = 16 32 | 33 | if torch.cuda.is_available(): 34 | device = "cuda" 35 | else: 36 | device = "cpu" 37 | 38 | controller = McFxLMS_algorithm(R_num=4, S_num=4, Len=Len_control, Sec=Sec_path, device=device) 39 | Erro = train_fxmclms_algorithm(Model=controller, Ref=Refer, Disturbance=Distu, device= device, Stepsize=0.000013) 40 | Wc_matrix = controller._get_coeff_() 41 | 42 | # Saving the mat 43 | Err_array = np.array(Erro) 44 | Save_data_to_mat(Mat_file_name ='Tst_4channel_program_McFxLMS.mat', Wc_matrix=Wc_matrix, Err_array=Err_array) 45 | print(Err_array.shape) 46 | 47 | # Drawing the impulse response of the primary path 48 | plt.title('The error signal of the FxLMS algorithm') 49 | plt.plot(Err_array[:,0]) 50 | plt.ylabel('Amplitude') 51 | plt.xlabel('Time') 52 | plt.grid() 53 | plt.show() 54 | 55 | fs=16000 56 | f, Pper_spec = signal.periodogram(Wc_matrix[0,0,:] , fs, 'flattop', scaling='spectrum') 57 | plt.semilogy(f, Pper_spec) 58 | plt.xlabel('frequency [Hz]') 59 | plt.ylabel('PSD') 60 | plt.grid() 61 | plt.show() 62 | 63 | -------------------------------------------------------------------------------- /Tst_4channel_ANC_program.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import torch 4 | import matplotlib.pyplot as plt 5 | import scipy.io as sio 6 | 7 | from Norimalized_Multichannel_FxLMS_algorithm import McFxNLMS_algorithm, train_McFxNLMS_algorithm, Disturbance_Noise_generation_from_Fvector 8 | from scipy.io import savemat 9 | from scipy import signal 10 | 11 | #------------------------------------------------------------ 12 | # Function : Save_data_to_mat() 13 | #------------------------------------------------------------ 14 | def Save_data_to_mat(Mat_file_name ='Tst_4channel_program.mat', **kwargs): 15 | mdict = {} 16 | for arg in kwargs: 17 | mdict[arg] = kwargs[arg] 18 | savemat(Mat_file_name, mdict) 19 | 20 | #------------------------------------------------------------ 21 | # Function : Load_noise_path_from_mat() 22 | # Loading primary path and noise from mat. 23 | #------------------------------------------------------------ 24 | def Load_noise_path_from_mat(Noise_mat_file='Noise_generation.mat', Path_mat_file='Path_generation.mat'): 25 | Refer_matrix = torch.from_numpy(sio.loadmat(Noise_mat_file)['Refer_matrix']).type(torch.float) 26 | Distur_matrix = torch.from_numpy(sio.loadmat(Noise_mat_file)['Distur_matrix']).type(torch.float) 27 | Primary_path_matrix = torch.from_numpy(sio.loadmat(Path_mat_file)['Primary_path_matrix']).type(torch.float) 28 | Secondary_path_matrix = torch.from_numpy(sio.loadmat(Path_mat_file)['Secondary_path_matrix']).type(torch.float) 29 | 30 | return Primary_path_matrix, Secondary_path_matrix, Refer_matrix, Distur_matrix 31 | 32 | #------------------------------------------------------------ 33 | if __name__ == "__main__": 34 | Pri_mat, Sec_mat, Refer_mat, Distur_mat = Load_noise_path_from_mat() 35 | 36 | Sec_path = torch.permute(Sec_mat,(2,0,1)) 37 | Refer = torch.permute(Refer_mat,(1,0)) 38 | Distu = torch.permute(Distur_mat,(1,0)) 39 | print(Refer.shape) 40 | 41 | #-------------------------------------------- 42 | Len_control = 512 43 | num_filters = 16 44 | #Wc_matrix = np.zeros((num_filters, Len_control), dtype=float) 45 | if torch.cuda.is_available(): 46 | device = "cuda" 47 | else: 48 | device = "cpu" 49 | 50 | controller = McFxNLMS_algorithm(R_num=4, S_num=4, Len=Len_control, Sec=Sec_path, device=device) 51 | Erro = train_McFxNLMS_algorithm(Model=controller, Ref=Refer, Disturbance=Distu, device= device, Stepsize=0.01) 52 | Wc_matrix = controller._get_coeff_() 53 | 54 | # Saving the mat 55 | Err_array = np.array(Erro) 56 | Save_data_to_mat(Mat_file_name ='Tst_4channel_program.mat', Wc_matrix=Wc_matrix, Err_array=Err_array) 57 | print(Err_array.shape) 58 | 59 | # Drawing the impulse response of the primary path 60 | plt.title('The error signal of the FxLMS algorithm') 61 | plt.plot(Err_array[:,0]) 62 | plt.ylabel('Amplitude') 63 | plt.xlabel('Time') 64 | plt.grid() 65 | plt.show() 66 | 67 | fs=16000 68 | f, Pper_spec = signal.periodogram(Wc_matrix[0,0,:] , fs, 'flattop', scaling='spectrum') 69 | plt.semilogy(f, Pper_spec) 70 | plt.xlabel('frequency [Hz]') 71 | plt.ylabel('PSD') 72 | plt.grid() 73 | plt.show() 74 | -------------------------------------------------------------------------------- /Tst_4channel_program.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShiDongyuan/Multichannel_FxLMS_python_code/0851cb2962de89da45d7df587839c1e19255c9dd/Tst_4channel_program.mat -------------------------------------------------------------------------------- /Tst_4channel_program_McFxLMS.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShiDongyuan/Multichannel_FxLMS_python_code/0851cb2962de89da45d7df587839c1e19255c9dd/Tst_4channel_program_McFxLMS.mat --------------------------------------------------------------------------------