從聲源定位(DOA)算法仿真到工程源碼實現-第八節

一、概述

? ? ? ? 本節我們記錄在respeaker core v2 開發板上部署一個完整的聲源定位(DOA)系統,演示可以看第一節中的視頻。整個模塊可以分為三部分,第一部分為控制開發板上的LED燈顯示,這樣可以實時的測試算法的效果;第二部分為從ALSA上取數據,我們這里需要取六通道的麥克風數據,加上最后兩個通道的回采信號,總共八個通道;第三部分為DOA算法部分,這里主要實現了SRP-PHAT算法。LED燈的控制程序和聲源定位算法程序是兩個進程同時運行,進程之間通過管道來通信,聲源定位算法向管道輸入定位的角度信息,LED燈的控制程序從管道獲取角度信息,進而控制燈的或亮或滅。

二、模塊解析

2.1 整體效果

? ? ? ??從聲源定位(DOA)算法仿真到工程源碼實現-第一節-CSDN博客

2.2 LED燈控

(1)代碼結構

respeaker_led
├── examples
│?? └── led_show.py
└── pixel_ring└── apa102.py

(2)led_show.py

import time
import sys
import os
import timesys.path.append("../pixel_ring/")
from apa102 import APA102class HiPixelRing(object):PIXELS_N = 12def __init__(self):self.dev = APA102(num_led=self.PIXELS_N)def off(self):for i in range(self.PIXELS_N):self.dev.set_pixel(i, 0, 0, 0)self.dev.show()self.dev.show()def wakeup(self, direction=0):led_num  = (direction + 15) // 30led_num = led_num % 12#led_num = int(led_num)for i in range(self.PIXELS_N):if i != led_num:self.dev.set_pixel(i, 0, 0, 0)else:self.dev.set_pixel(i, 10, 10, 10)self.dev.show()if __name__ == '__main__':pixel_ring = HiPixelRing()direction = 0input_file = "/tmp/node2_to_node1.tmp"# 1.create fifoif not os.path.exists(input_file):os.mkfifo(input_file, 0o666)# 2.open pipeprint('init read pipe:  ' + input_file)fin = os.open(input_file, os.O_RDONLY)val = ""while True:try:#recv_str = os.read(fin, 1024).decode()[:-1]recv_str = os.read(fin, 1).decode()if recv_str != 'T':val += recv_strcontinueelse:recv_str = valval = ""print("recv:{}".format(recv_str))direction = int(recv_str)pixel_ring.wakeup(direction)#direction += 30#time.sleep(0.5)except KeyboardInterrupt:breakos.close(fin)pixel_ring.off()time.sleep(1)

(3)apa102.py

"""
from https://github.com/tinue/APA102_Pi
This is the main driver module for APA102 LEDs
"""
import spidev
from math import ceilRGB_MAP = { 'rgb': [3, 2, 1], 'rbg': [3, 1, 2], 'grb': [2, 3, 1],'gbr': [2, 1, 3], 'brg': [1, 3, 2], 'bgr': [1, 2, 3] }class APA102:"""Driver for APA102 LEDS (aka "DotStar").(c) Martin Erzberger 2016-2017My very first Python code, so I am sure there is a lot to be optimized ;)Public methods are:- set_pixel- set_pixel_rgb- show- clear_strip- cleanupHelper methods for color manipulation are:- combine_color- wheelThe rest of the methods are used internally and should not be used by theuser of the library.Very brief overview of APA102: An APA102 LED is addressed with SPI. The bitsare shifted in one by one, starting with the least significant bit.An LED usually just forwards everything that is sent to its data-in todata-out. While doing this, it remembers its own color and keeps glowingwith that color as long as there is power.An LED can be switched to not forward the data, but instead use the datato change it's own color. This is done by sending (at least) 32 bits ofzeroes to data-in. The LED then accepts the next correct 32 bit LEDframe (with color information) as its new color setting.After having received the 32 bit color frame, the LED changes color,and then resumes to just copying data-in to data-out.The really clever bit is this: While receiving the 32 bit LED frame,the LED sends zeroes on its data-out line. Because a color frame is32 bits, the LED sends 32 bits of zeroes to the next LED.As we have seen above, this means that the next LED is now readyto accept a color frame and update its color.So that's really the entire protocol:- Start by sending 32 bits of zeroes. This prepares LED 1 to updateits color.- Send color information one by one, starting with the color for LED 1,then LED 2 etc.- Finish off by cycling the clock line a few times to get all datato the very last LED on the stripThe last step is necessary, because each LED delays forwarding the dataa bit. Imagine ten people in a row. When you yell the last colorinformation, i.e. the one for person ten, to the first person inthe line, then you are not finished yet. Person one has to turn aroundand yell it to person 2, and so on. So it takes ten additional "dummy"cycles until person ten knows the color. When you look closer,you will see that not even person 9 knows its own color yet. Thisinformation is still with person 2. Essentially the driver sends additionalzeroes to LED 1 as long as it takes for the last color frame to make itdown the line to the last LED."""# ConstantsMAX_BRIGHTNESS = 0b11111 # Safeguard: Set to a value appropriate for your setupLED_START = 0b11100000 # Three "1" bits, followed by 5 brightness bitsdef __init__(self, num_led, global_brightness=MAX_BRIGHTNESS,order='rgb', bus=0, device=1, max_speed_hz=8000000):self.num_led = num_led  # The number of LEDs in the Striporder = order.lower()self.rgb = RGB_MAP.get(order, RGB_MAP['rgb'])# Limit the brightness to the maximum if it's set higherif global_brightness > self.MAX_BRIGHTNESS:self.global_brightness = self.MAX_BRIGHTNESSelse:self.global_brightness = global_brightnessself.leds = [self.LED_START,0,0,0] * self.num_led # Pixel bufferself.spi = spidev.SpiDev()  # Init the SPI deviceself.spi.open(bus, device)  # Open SPI port 0, slave device (CS) 1# Up the speed a bit, so that the LEDs are painted fasterif max_speed_hz:self.spi.max_speed_hz = max_speed_hzdef clock_start_frame(self):"""Sends a start frame to the LED strip.This method clocks out a start frame, telling the receiving LEDthat it must update its own color now."""self.spi.xfer2([0] * 4)  # Start frame, 32 zero bitsdef clock_end_frame(self):"""Sends an end frame to the LED strip.As explained above, dummy data must be sent after the last real colourinformation so that all of the data can reach its destination down the line.The delay is not as bad as with the human example above.It is only 1/2 bit per LED. This is because the SPI clock lineneeds to be inverted.Say a bit is ready on the SPI data line. The sender communicatesthis by toggling the clock line. The bit is read by the LEDand immediately forwarded to the output data line. When the clock goesdown again on the input side, the LED will toggle the clock upon the output to tell the next LED that the bit is ready.After one LED the clock is inverted, and after two LEDs it is in syncagain, but one cycle behind. Therefore, for every two LEDs, one bitof delay gets accumulated. For 300 LEDs, 150 additional bits must be fed tothe input of LED one so that the data can reach the last LED.Ultimately, we need to send additional numLEDs/2 arbitrary data bits,in order to trigger numLEDs/2 additional clock changes. This driversends zeroes, which has the benefit of getting LED one partially orfully ready for the next update to the strip. An optimized versionof the driver could omit the "clockStartFrame" method if enough zeroes havebeen sent as part of "clockEndFrame"."""self.spi.xfer2([0xFF] * 4)# Round up num_led/2 bits (or num_led/16 bytes)#for _ in range((self.num_led + 15) // 16):#    self.spi.xfer2([0x00])def clear_strip(self):""" Turns off the strip and shows the result right away."""for led in range(self.num_led):self.set_pixel(led, 0, 0, 0)self.show()def set_pixel(self, led_num, red, green, blue, bright_percent=100):"""Sets the color of one pixel in the LED stripe.The changed pixel is not shown yet on the Stripe, it is onlywritten to the pixel buffer. Colors are passed individually.If brightness is not set the global brightness setting is used."""if led_num < 0:return  # Pixel is invisible, so ignoreif led_num >= self.num_led:return  # again, invisible# Calculate pixel brightness as a percentage of the# defined global_brightness. Round up to nearest integer# as we expect some brightness unless set to 0brightness = int(ceil(bright_percent*self.global_brightness/100.0))# LED startframe is three "1" bits, followed by 5 brightness bitsledstart = (brightness & 0b00011111) | self.LED_STARTstart_index = 4 * led_numself.leds[start_index] = ledstartself.leds[start_index + self.rgb[0]] = redself.leds[start_index + self.rgb[1]] = greenself.leds[start_index + self.rgb[2]] = bluedef set_pixel_rgb(self, led_num, rgb_color, bright_percent=100):"""Sets the color of one pixel in the LED stripe.The changed pixel is not shown yet on the Stripe, it is onlywritten to the pixel buffer.Colors are passed combined (3 bytes concatenated)If brightness is not set the global brightness setting is used."""self.set_pixel(led_num, (rgb_color & 0xFF0000) >> 16,(rgb_color & 0x00FF00) >> 8, rgb_color & 0x0000FF,bright_percent)def rotate(self, positions=1):""" Rotate the LEDs by the specified number of positions.Treating the internal LED array as a circular buffer, rotate it bythe specified number of positions. The number could be negative,which means rotating in the opposite direction."""cutoff = 4 * (positions % self.num_led)self.leds = self.leds[cutoff:] + self.leds[:cutoff]def show(self):"""Sends the content of the pixel buffer to the strip.Todo: More than 1024 LEDs requires more than one xfer operation."""self.clock_start_frame()# xfer2 kills the list, unfortunately. So it must be copied first# SPI takes up to 4096 Integers. So we are fine for up to 1024 LEDs.data = list(self.leds)while data:self.spi.xfer2(data[:32])data = data[32:]self.clock_end_frame()def cleanup(self):"""Release the SPI device; Call this method at the end"""self.spi.close()  # Close SPI port@staticmethoddef combine_color(red, green, blue):"""Make one 3*8 byte color value."""return (red << 16) + (green << 8) + bluedef wheel(self, wheel_pos):"""Get a color from a color wheel; Green -> Red -> Blue -> Green"""if wheel_pos > 255:wheel_pos = 255 # Safeguardif wheel_pos < 85:  # Green -> Redreturn self.combine_color(wheel_pos * 3, 255 - wheel_pos * 3, 0)if wheel_pos < 170:  # Red -> Bluewheel_pos -= 85return self.combine_color(255 - wheel_pos * 3, 0, wheel_pos * 3)# Blue -> Greenwheel_pos -= 170return self.combine_color(0, wheel_pos * 3, 255 - wheel_pos * 3)def dump_array(self):"""For debug purposes: Dump the LED array onto the console."""print(self.leds)

2.3 ALSA取數據

(1)ALSA讀數據及DOA算法調用

#define ALSA_PCM_NEW_HW_PARAMS_API#include <alsa/asoundlib.h>
#include <stdio.h>
#include "doa-api.h"
#define NUM_FRAMES 160
#define OUTPUT_PATH_NAME "/tmp/node2_to_node1.tmp"int main() {int fout = open(OUTPUT_PATH_NAME, O_WRONLY);char buffer2[1024];    long loops;int rc;int size;unsigned int val;int dir;char *buffer;snd_pcm_t *handle;snd_pcm_hw_params_t *params;snd_pcm_uframes_t frames;int mic_num = 6;float radius = 0.0465;int channel_num = 8;void *handle1 = api_create_doa_handle(mic_num, radius);//short *input_data = (short*)malloc(sizeof(short) * channel_num * NUM_FRAMES);float *inp_float = (float*)malloc(sizeof(float) * mic_num * NUM_FRAMES);/*以錄制模式打開*//* Open PCM device for recording (capture). */rc = snd_pcm_open( &handle, "default", SND_PCM_STREAM_CAPTURE, 0);if (rc < 0) {fprintf(stderr, "unable to open pcm device");exit(EXIT_FAILURE);}/*分配一個參數對象*//* Allocate a hardware parameters object. */snd_pcm_hw_params_alloca(&params);/*初始化參數對象*//* Fill it in with default values. */rc = snd_pcm_hw_params_any(handle, params);if (rc < 0) {printf("Err\n");}/* Set the desired hardware parameters. *//*交錯模式*//* Interleaved mode */rc = snd_pcm_hw_params_set_access(handle, params,SND_PCM_ACCESS_RW_INTERLEAVED);if (rc < 0) {printf("Err\n");}/*PCM格式*//* Signed 16-bit little-endian format */rc = snd_pcm_hw_params_set_format(handle, params,SND_PCM_FORMAT_S16_LE);if (rc < 0) {printf("Err\n");}/*設置通道數*//* Two channels (stereo) */rc = snd_pcm_hw_params_set_channels(handle, params, 8);if (rc < 0) {printf("Err\n");}/*設置采樣率*//* 44100 bits/second sampling rate (CD quality) */val = 16000;rc = snd_pcm_hw_params_set_rate_near(handle, params,&val, &dir);if (rc < 0) {printf("Err\n");}/*沒周期的幀數*//* Set period size to 32 frames. */frames = 160;rc = snd_pcm_hw_params_set_period_size_near(handle,params, &frames, &dir);if (rc < 0) {printf("Err\n");}/* Write the parameters to the driver */rc = snd_pcm_hw_params(handle, params);if (rc < 0) {fprintf(stderr,"unable to set hw parameters: %s/n",snd_strerror(rc));exit(1);}/* Use a buffer large enough to hold one period */rc = snd_pcm_hw_params_get_period_size(params,&frames, &dir);if (rc < 0) {printf("Err\n");}size = frames * 2 * 8; /* 2 bytes/sample, 2 channels */buffer = (char *) malloc(size);/* We want to loop for 5 seconds */rc = snd_pcm_hw_params_get_period_time(params, &val, &dir);loops = 5000000 / val;printf("====================:%ld\n", frames);printf("====================\n");printf("====================\n");FILE *fp = fopen("record.pcm", "wb");while (loops > 0) {//loops--;rc = snd_pcm_readi(handle, buffer, frames);if (rc == -EPIPE) {/* EPIPE means overrun */fprintf(stderr, "overrun occurred/n");//把PCM流置于PREPARED狀態,這樣下次我們向該PCM流中數據時,它就能重新開始處理數據。snd_pcm_prepare(handle);} else if (rc < 0) {fprintf(stderr,"error from read: %s/n",snd_strerror(rc));} else if (rc != (int)frames) {fprintf(stderr, "short read, read %d frames/n", rc);}//rc = write(1, buffer, size);short *input_data_x = (short*)buffer;for (int i = 0; i < NUM_FRAMES; i++) {for (int j = 0; j < mic_num; j++) {inp_float[i*mic_num+j] = input_data_x[i*channel_num+j];}}int angle = api_process_doa(handle1, inp_float, NUM_FRAMES);memset(buffer2, 0, sizeof(buffer2));sprintf(buffer2, "%dT", angle);if (write(fout, buffer2, strlen(buffer2)) <= 0) {break;}printf(">>> %d\n", angle);/*rc = fwrite(buffer, 1, size, fp);if (rc != size)fprintf(stderr,"short write: wrote %d bytes/n", rc);*/}//調用snd_pcm_drain把所有掛起沒有傳輸完的聲音樣本傳輸完全rc = snd_pcm_drain(handle);//關閉該音頻流,釋放之前動態分配的緩沖區,退出rc = snd_pcm_close(handle);free(buffer);fclose(fp);api_destroy_doa_handle(handle1);return 0;
}

2.4 DOA算法

(1)代碼結構

doa
├── CMakeLists.txt
├── bin
│?? ├── CMakeLists.txt
│?? ├── alsa-doa.c
│?? └── test-doa.c
├── build
│?? ├── CMakeCache.txt
│?? ├── CMakeFiles
│?? │?? ├── 3.22.1
│?? │?? │?? ├── CMakeCCompiler.cmake
│?? │?? │?? ├── CMakeCXXCompiler.cmake
│?? │?? │?? ├── CMakeDetermineCompilerABI_C.bin
│?? │?? │?? ├── CMakeDetermineCompilerABI_CXX.bin
│?? │?? │?? ├── CMakeSystem.cmake
│?? │?? │?? ├── CompilerIdC
│?? │?? │?? │?? ├── CMakeCCompilerId.c
│?? │?? │?? │?? ├── a.out
│?? │?? │?? │?? └── tmp
│?? │?? │?? └── CompilerIdCXX
│?? │?? │??     ├── CMakeCXXCompilerId.cpp
│?? │?? │??     ├── a.out
│?? │?? │??     └── tmp
│?? │?? ├── CMakeDirectoryInformation.cmake
│?? │?? ├── CMakeOutput.log
│?? │?? ├── CMakeTmp
│?? │?? ├── Makefile.cmake
│?? │?? ├── Makefile2
│?? │?? ├── TargetDirectories.txt
│?? │?? ├── cmake.check_cache
│?? │?? └── progress.marks
│?? ├── Makefile
│?? ├── bin
│?? │?? ├── CMakeFiles
│?? │?? │?? ├── CMakeDirectoryInformation.cmake
│?? │?? │?? ├── alsa-doa.dir
│?? │?? │?? │?? ├── DependInfo.cmake
│?? │?? │?? │?? ├── alsa-doa.c.o
│?? │?? │?? │?? ├── alsa-doa.c.o.d
│?? │?? │?? │?? ├── build.make
│?? │?? │?? │?? ├── cmake_clean.cmake
│?? │?? │?? │?? ├── compiler_depend.make
│?? │?? │?? │?? ├── compiler_depend.ts
│?? │?? │?? │?? ├── depend.make
│?? │?? │?? │?? ├── flags.make
│?? │?? │?? │?? ├── link.txt
│?? │?? │?? │?? └── progress.make
│?? │?? │?? ├── progress.marks
│?? │?? │?? └── test-doa.dir
│?? │?? │??     ├── DependInfo.cmake
│?? │?? │??     ├── build.make
│?? │?? │??     ├── cmake_clean.cmake
│?? │?? │??     ├── compiler_depend.make
│?? │?? │??     ├── compiler_depend.ts
│?? │?? │??     ├── depend.make
│?? │?? │??     ├── flags.make
│?? │?? │??     ├── link.txt
│?? │?? │??     ├── progress.make
│?? │?? │??     ├── test-doa.c.o
│?? │?? │??     └── test-doa.c.o.d
│?? │?? ├── Makefile
│?? │?? ├── alsa-doa
│?? │?? ├── cmake_install.cmake
│?? │?? └── test-doa
│?? ├── cmake_install.cmake
│?? └── src
│??     ├── CMakeFiles
│??     │?? ├── CMakeDirectoryInformation.cmake
│??     │?? ├── mouse-doa.dir
│??     │?? │?? ├── DependInfo.cmake
│??     │?? │?? ├── build.make
│??     │?? │?? ├── cmake_clean.cmake
│??     │?? │?? ├── cmake_clean_target.cmake
│??     │?? │?? ├── compiler_depend.make
│??     │?? │?? ├── compiler_depend.ts
│??     │?? │?? ├── depend.make
│??     │?? │?? ├── doa-api.c.o
│??     │?? │?? ├── doa-api.c.o.d
│??     │?? │?? ├── doa-blocker.c.o
│??     │?? │?? ├── doa-blocker.c.o.d
│??     │?? │?? ├── doa-complex.c.o
│??     │?? │?? ├── doa-complex.c.o.d
│??     │?? │?? ├── doa-fft.c.o
│??     │?? │?? ├── doa-fft.c.o.d
│??     │?? │?? ├── doa-impl.c.o
│??     │?? │?? ├── doa-impl.c.o.d
│??     │?? │?? ├── doa-matrix.c.o
│??     │?? │?? ├── doa-matrix.c.o.d
│??     │?? │?? ├── fft4g.c.o
│??     │?? │?? ├── fft4g.c.o.d
│??     │?? │?? ├── flags.make
│??     │?? │?? ├── link.txt
│??     │?? │?? ├── progress.make
│??     │?? │?? ├── ring_buffer.c.o
│??     │?? │?? └── ring_buffer.c.o.d
│??     │?? └── progress.marks
│??     ├── Makefile
│??     ├── cmake_install.cmake
│??     └── libmouse-doa.a
├── src
│?? ├── CMakeLists.txt
│?? ├── doa-api.c
│?? ├── doa-api.h
│?? ├── doa-blocker.c
│?? ├── doa-blocker.h
│?? ├── doa-complex.c
│?? ├── doa-complex.h
│?? ├── doa-fft.c
│?? ├── doa-fft.h
│?? ├── doa-impl.c
│?? ├── doa-impl.h
│?? ├── doa-matrix.c
│?? ├── doa-matrix.h
│?? ├── doa-types.h
│?? ├── fft4g.c
│?? ├── fft4g.h
│?? ├── ring_buffer.c
│?? └── ring_buffer.h
└── test└── 120du-180du.pcm

(2)doa-api.c

/**@author : aflyingwolf*@date   : 2025.3.20*@file   : doa-api.c* */
#include "doa-api.h"
#include "doa-blocker.h"
#include "doa-fft.h"
#include "doa-types.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>static float mouse_FloatS16ToFloat(float v) {static const float kMaxInt16Inverse = 1.0 / 32767;static const float kMinInt16Inverse = 1.0 / -32768;return v * (v > 0 ? kMaxInt16Inverse : -kMinInt16Inverse);
}/*
static float mouse_FloatToFloatS16(float v) {return v * (v > 0 ? 32767.0 : 32768.0);
}*/typedef struct mouse_DoaHandle_ {mouse_blocker *blocker_;float **in_buf_;int mic_num_;mouse_doa *doa_inst_;
} mouse_DoaHandle;void *api_create_doa_handle(int mic_num, float radius) {mouse_doa *doa_inst = mouse_doa_instance(kSampleRate,mic_num,radius);//hamming windowsfloat window[512] = {0.08,0.08003477,0.08013909,0.08031292,0.08055626,0.08086906,0.08125127,0.08170284,0.0822237,0.08281376,0.08347295,0.08420116,0.08499828,0.08586418,0.08679875,0.08780184,0.08887329,0.09001294,0.09122063,0.09249617,0.09383936,0.09525001,0.09672789,0.0982728,0.09988448,0.10156271,0.10330722,0.10511775,0.10699403,0.10893578,0.1109427,0.11301448,0.11515082,0.11735139,0.11961586,0.12194389,0.12433512,0.12678919,0.12930573,0.13188437,0.13452471,0.13722635,0.13998888,0.14281189,0.14569495,0.14863762,0.15163946,0.15470002,0.15781883,0.16099542,0.16422931,0.16752001,0.17086702,0.17426984,0.17772796,0.18124085,0.18480797,0.1884288,0.19210278,0.19582935,0.19960796,0.20343803,0.20731899,0.21125024,0.2152312,0.21926125,0.2233398,0.22746622,0.2316399,0.23586019,0.24012646,0.24443807,0.24879437,0.25319469,0.25763837,0.26212475,0.26665313,0.27122284,0.27583319,0.28048347,0.28517299,0.28990103,0.29466689,0.29946984,0.30430915,0.3091841,0.31409394,0.31903793,0.32401534,0.32902539,0.33406735,0.33914043,0.34424389,0.34937694,0.35453881,0.35972872,0.36494588,0.37018951,0.37545881,0.38075299,0.38607124,0.39141277,0.39677676,0.4021624,0.40756889,0.41299539,0.4184411,0.42390518,0.42938682,0.43488518,0.44039943,0.44592874,0.45147227,0.45702919,0.46259865,0.46817981,0.47377183,0.47937386,0.48498506,0.49060458,0.49623157,0.50186517,0.50750453,0.51314881,0.51879715,0.5244487,0.5301026,0.53575799,0.54141402,0.54706984,0.55272459,0.55837742,0.56402747,0.56967389,0.57531582,0.58095241,0.58658281,0.59220616,0.59782163,0.60342835,0.60902548,0.61461218,0.6201876,0.62575089,0.63130122,0.63683774,0.64235963,0.64786604,0.65335614,0.6588291,0.6642841,0.66972031,0.67513691,0.68053307,0.68590799,0.69126085,0.69659084,0.70189716,0.707179,0.71243557,0.71766606,0.72286969,0.72804568,0.73319324,0.73831159,0.74339995,0.74845757,0.75348367,0.75847749,0.76343829,0.7683653,0.77325778,0.77811501,0.78293623,0.78772072,0.79246776,0.79717663,0.80184662,0.80647702,0.81106714,0.81561627,0.82012373,0.82458885,0.82901093,0.83338932,0.83772336,0.84201238,0.84625575,0.85045281,0.85460293,0.8587055,0.86275987,0.86676546,0.87072163,0.87462781,0.8784834,0.88228781,0.88604048,0.88974082,0.89338829,0.89698234,0.90052241,0.90400798,0.90743851,0.91081349,0.91413241,0.91739477,0.92060007,0.92374783,0.92683757,0.92986882,0.93284114,0.93575406,0.93860715,0.94139997,0.94413211,0.94680315,0.94941269,0.95196032,0.95444568,0.95686838,0.95922805,0.96152434,0.9637569,0.9659254,0.9680295,0.97006889,0.97204326,0.97395231,0.97579575,0.97757331,0.97928471,0.98092969,0.98250802,0.98401944,0.98546374,0.98684068,0.98815007,0.98939171,0.9905654,0.99167097,0.99270826,0.99367711,0.99457736,0.99540889,0.99617157,0.99686528,0.99748992,0.99804539,0.99853161,0.99894851,0.99929602,0.99957409,0.99978268,0.99992176,0.99999131,0.99999131,0.99992176,0.99978268,0.99957409,0.99929602,0.99894851,0.99853161,0.99804539,0.99748992,0.99686528,0.99617157,0.99540889,0.99457736,0.99367711,0.99270826,0.99167097,0.9905654,0.98939171,0.98815007,0.98684068,0.98546374,0.98401944,0.98250802,0.98092969,0.97928471,0.97757331,0.97579575,0.97395231,0.97204326,0.97006889,0.9680295,0.9659254,0.9637569,0.96152434,0.95922805,0.95686838,0.95444568,0.95196032,0.94941269,0.94680315,0.94413211,0.94139997,0.93860715,0.93575406,0.93284114,0.92986882,0.92683757,0.92374783,0.92060007,0.91739477,0.91413241,0.91081349,0.90743851,0.90400798,0.90052241,0.89698234,0.89338829,0.88974082,0.88604048,0.88228781,0.8784834,0.87462781,0.87072163,0.86676546,0.86275987,0.8587055,0.85460293,0.85045281,0.84625575,0.84201238,0.83772336,0.83338932,0.82901093,0.82458885,0.82012373,0.81561627,0.81106714,0.80647702,0.80184662,0.79717663,0.79246776,0.78772072,0.78293623,0.77811501,0.77325778,0.7683653,0.76343829,0.75847749,0.75348367,0.74845757,0.74339995,0.73831159,0.73319324,0.72804568,0.72286969,0.71766606,0.71243557,0.707179,0.70189716,0.69659084,0.69126085,0.68590799,0.68053307,0.67513691,0.66972031,0.6642841,0.6588291,0.65335614,0.64786604,0.64235963,0.63683774,0.63130122,0.62575089,0.6201876,0.61461218,0.60902548,0.60342835,0.59782163,0.59220616,0.58658281,0.58095241,0.57531582,0.56967389,0.56402747,0.55837742,0.55272459,0.54706984,0.54141402,0.53575799,0.5301026,0.5244487,0.51879715,0.51314881,0.50750453,0.50186517,0.49623157,0.49060458,0.48498506,0.47937386,0.47377183,0.46817981,0.46259865,0.45702919,0.45147227,0.44592874,0.44039943,0.43488518,0.42938682,0.42390518,0.4184411,0.41299539,0.40756889,0.4021624,0.39677676,0.39141277,0.38607124,0.38075299,0.37545881,0.37018951,0.36494588,0.35972872,0.35453881,0.34937694,0.34424389,0.33914043,0.33406735,0.32902539,0.32401534,0.31903793,0.31409394,0.3091841,0.30430915,0.29946984,0.29466689,0.28990103,0.28517299,0.28048347,0.27583319,0.27122284,0.26665313,0.26212475,0.25763837,0.25319469,0.24879437,0.24443807,0.24012646,0.23586019,0.2316399,0.22746622,0.2233398,0.21926125,0.2152312,0.21125024,0.20731899,0.20343803,0.19960796,0.19582935,0.19210278,0.1884288,0.18480797,0.18124085,0.17772796,0.17426984,0.17086702,0.16752001,0.16422931,0.16099542,0.15781883,0.15470002,0.15163946,0.14863762,0.14569495,0.14281189,0.13998888,0.13722635,0.13452471,0.13188437,0.12930573,0.12678919,0.12433512,0.12194389,0.11961586,0.11735139,0.11515082,0.11301448,0.1109427,0.10893578,0.10699403,0.10511775,0.10330722,0.10156271,0.09988448,0.0982728,0.09672789,0.09525001,0.09383936,0.09249617,0.09122063,0.09001294,0.08887329,0.08780184,0.08679875,0.08586418,0.08499828,0.08420116,0.08347295,0.08281376,0.0822237,0.08170284,0.08125127,0.08086906,0.08055626,0.08031292,0.08013909,0.08003477,0.08};mouse_blocker *blocker = mouse_blocker_instance(160,512,mic_num,window,128,mouse_doa_process_block,doa_inst);mouse_DoaHandle *handle = (mouse_DoaHandle*)malloc(sizeof(mouse_DoaHandle));handle->blocker_ = blocker;handle->doa_inst_ = doa_inst;handle->in_buf_ = (float**)malloc(sizeof(float*) * mic_num);handle->mic_num_ = mic_num;for (int i = 0; i < mic_num; i++) {handle->in_buf_[i] = (float*)malloc(sizeof(float) * 160);}return (void*)handle;
}void api_destroy_doa_handle(void *handle) {mouse_DoaHandle *handle_ = (mouse_DoaHandle *)handle;mouse_doa_destroy(handle_->doa_inst_);mouse_blocker_destroy(handle_->blocker_);for (int i = 0; i < handle_->mic_num_; i++) {free(handle_->in_buf_[i]);}free(handle_->in_buf_);free(handle_);
}int api_start_doa(void *handle) {return 0;
}int api_process_doa(void *handle, float *input_data, int chunk_size) {mouse_DoaHandle *handle_ = (mouse_DoaHandle *)handle;for (int j = 0; j < chunk_size; j++) {for (int i = 0; i < handle_->mic_num_; i++) {handle_->in_buf_[i][j] = mouse_FloatS16ToFloat(input_data[j*handle_->mic_num_ + i]);}}int angle = mouse_blocker_process_chunk(handle_->blocker_,handle_->in_buf_,chunk_size,handle_->mic_num_);return angle;
}
int api_end_doa(void *handle) {return 0;
}

(3)doa-blocker.c

/**@author : aflyingwolf*@date   : 2025.3.20*@file   : doa-blocker.c* */#include "doa-blocker.h"
#include "doa-impl.h"#include <string.h>
#include <stdlib.h>
#include <assert.h>// Pointwise multiplies each channel of |frames| with |window|. Results are
// stored in |frames|.
static void mouse_ApplyWindow(const float* window,size_t num_frames,int num_channels,float* const* frames) {for (int i = 0; i < num_channels; ++i) {for (size_t j = 0; j < num_frames; ++j) {frames[i][j] = frames[i][j] * window[j];}}
}static size_t mouse_gcd(size_t a, size_t b) {size_t tmp;while (b) {tmp = a;a = b;b = tmp % b;}return a;
}mouse_blocker *mouse_blocker_instance(size_t chunk_size,size_t block_size,int num_input_channels,const float* window,size_t shift_amount,mouse_CallbackDoa callback,mouse_doa *doa_inst) {mouse_blocker *inst = (mouse_blocker*)malloc(sizeof(mouse_blocker));inst->chunk_size_ = chunk_size;inst->block_size_ = block_size;inst->num_input_channels_ = num_input_channels;inst->initial_delay_ = block_size - mouse_gcd(chunk_size, shift_amount);inst->frame_offset_ = 0;inst->input_buffer_ = (RingBuffer**)malloc(sizeof(RingBuffer*) * num_input_channels);for (int i = 0; i < num_input_channels; i++) {inst->input_buffer_[i] = WebRtc_CreateBuffer(inst->chunk_size_ + inst->initial_delay_, sizeof(float));}inst->input_block_ = (float**)malloc(sizeof(float*) * num_input_channels);for (int i = 0; i < num_input_channels; i++) {inst->input_block_[i] = (float*)malloc(sizeof(float) * block_size);}inst->window_ = (float*)malloc(sizeof(float) * block_size);inst->shift_amount_ = shift_amount;memcpy(inst->window_, window, block_size * sizeof(float));for (int i = 0; i < num_input_channels; i++) {int moved = WebRtc_MoveReadPtr(inst->input_buffer_[i], -inst->initial_delay_);assert(moved == -inst->initial_delay_);}inst->fft_inst_ = mouse_fft_instance(inst->block_size_);inst->fft_input_block_ = (mouse_complex_f**)malloc(sizeof(mouse_complex_f*) * num_input_channels);for (int i = 0; i < num_input_channels; i++) {inst->fft_input_block_[i] = (mouse_complex_f*)malloc(sizeof(mouse_complex_f) * inst->fft_inst_->complex_length_);}inst->callback_ = callback;inst->doa_inst_ = doa_inst;return inst;
}// destroy a blocker.
void mouse_blocker_destroy(mouse_blocker *inst) {for (int i = 0; i < inst->num_input_channels_; i++) {WebRtc_FreeBuffer(inst->input_buffer_[i]);}free(inst->input_buffer_);for (int i = 0; i < inst->num_input_channels_; i++) {free(inst->input_block_[i]);}free(inst->input_block_);free(inst->window_);mouse_fft_destroy(inst->fft_inst_);for (int i = 0; i < inst->num_input_channels_; i++) {free(inst->fft_input_block_[i]);}free(inst->fft_input_block_);free(inst);
}//process a chunk data.
int mouse_blocker_process_chunk(mouse_blocker *inst,float** input,size_t chunk_size,int num_input_channels) {for (size_t i = 0; i < num_input_channels; ++i) {WebRtc_WriteBuffer(inst->input_buffer_[i], input[i], chunk_size);}size_t first_frame_in_block = inst->frame_offset_;// Loop through blocks.while (first_frame_in_block < inst->chunk_size_) {for (int i = 0; i < inst->num_input_channels_; i++) {WebRtc_ReadBuffer(inst->input_buffer_[i], NULL, inst->input_block_[i], inst->block_size_);WebRtc_MoveReadPtr(inst->input_buffer_[i], -(inst->block_size_ - inst->shift_amount_));}mouse_ApplyWindow(inst->window_, inst->block_size_, inst->num_input_channels_, inst->input_block_);for (int i = 0; i < inst->num_input_channels_; i++) {mouse_fft_forward(inst->fft_inst_, inst->input_block_[i], inst->fft_input_block_[i]);}inst->doa_angle_ = inst->callback_(inst->doa_inst_, inst->fft_input_block_, inst->num_input_channels_, kNumFreqBins);first_frame_in_block += inst->shift_amount_;}// Calculate new starting frames.inst->frame_offset_ = first_frame_in_block - inst->chunk_size_;return inst->doa_angle_;
}

(4)doa-impl.c

/**@author : aflyingwolf*@date   : 2025.3.20*@file   : doa-impl.c* */
#include "doa-impl.h"
#include <stdlib.h>
#include <math.h>mouse_doa *mouse_doa_instance(int sample_rate_hz,int mic_num,float radius) {mouse_doa *inst = (mouse_doa*)malloc(sizeof(mouse_doa));inst->sample_rate_hz_ = sample_rate_hz;inst->num_input_channels_ = mic_num;inst->radius_ = radius;inst->step_ = 30;inst->num_direction_ = 360.0 / inst->step_;inst->mic_angle_ = (float*)malloc(sizeof(float)*inst->num_input_channels_);inst->mic_angle_[0] = 300;inst->mic_angle_[1] = 0;inst->mic_angle_[2] = 60;inst->mic_angle_[3] = 120;inst->mic_angle_[4] = 180;inst->mic_angle_[5] = 240;inst->smooth_len_ = 20;inst->P_ = (float**)malloc(sizeof(float*) * inst->num_direction_);for (int i = 0; i < inst->num_direction_; i++) {inst->P_[i] = (float*)malloc(sizeof(float) * inst->smooth_len_);for (int j = 0; j < inst->smooth_len_; j++) {inst->P_[i][j] = 0.0;}}inst->H_ = (mouse_complex_matrix_f*)malloc(sizeof(mouse_complex_matrix_f) * inst->num_direction_);for (int i = 0; i < inst->num_direction_; i++) {mouse_complex_matrix_init(&(inst->H_[i]), inst->num_input_channels_, kNumFreqBins);float direction = i * inst->step_;mouse_complex_f **mat_els = inst->H_[i].elements_;for (int j = 0; j < inst->num_input_channels_; j++) {float tao = inst->radius_ * sin(90.0 * M_PI / 180.0) * cos((direction - inst->mic_angle_[j]) * M_PI / 180.0) / 340.0;for (int k = 0; k < kNumFreqBins; k++) {float omega = 2.0 * M_PI * k * inst->sample_rate_hz_ / kFftSize;float x = -1.0 * omega * tao;mat_els[j][k].real_ = cos(x);mat_els[j][k].imag_ = sin(x);}}}inst->data_abs_ = (float**)malloc(sizeof(float*) * inst->num_input_channels_);inst->mid_res_ = (mouse_complex_f**)malloc(sizeof(mouse_complex_f*) * inst->num_input_channels_);for (int k = 0; k < inst->num_input_channels_; k++) {inst->data_abs_[k] = (float*)malloc(sizeof(float) * kNumFreqBins);inst->mid_res_[k] = (mouse_complex_f*)malloc(sizeof(mouse_complex_f) * kNumFreqBins);}inst->frame_id_ = 0;inst->start_ = 0;inst->end_ = 128;return inst;
}void mouse_doa_destroy(mouse_doa *inst) {free(inst->mic_angle_);for (int i = 0; i < inst->num_direction_; i++) {free(inst->P_[i]);}free(inst->P_);for (int i = 0; i < inst->num_direction_; i++) {mouse_complex_matrix_free(&(inst->H_[i]));}free(inst->H_);for (int i = 0; i < inst->num_input_channels_; i++) {free(inst->data_abs_[i]);free(inst->mid_res_[i]);}free(inst->data_abs_);free(inst->mid_res_);free(inst);
}void mouse_doa_reset(mouse_doa *inst) {return;
}int mouse_doa_process_block(mouse_doa *inst,mouse_complex_f** input,int num_input_channels,size_t num_freq_bins) {for (int j = 0; j < inst->num_input_channels_; j++) {for (int k = inst->start_; k < inst->end_; k++) {inst->data_abs_[j][k] = sqrt(input[j][k].real_ * input[j][k].real_ + input[j][k].imag_ * input[j][k].imag_);}}//return 45;int max_id = 0;float max_val = 0.0;for (int i = 0; i < inst->num_direction_; i++) {mouse_complex_f **mat_els = inst->H_[i].elements_;for (int j = 0; j < inst->num_input_channels_; j++) {for (int k = inst->start_; k < inst->end_; k++) {inst->mid_res_[j][k] = mouse_complex_mul(mat_els[j][k], input[j][k]);inst->mid_res_[j][k].real_ /= inst->data_abs_[j][k];inst->mid_res_[j][k].imag_ /= inst->data_abs_[j][k];}}for (int j = 1; j < inst->num_input_channels_; j++) {for (int k = inst->start_; k < inst->end_; k++) {inst->mid_res_[0][k] = mouse_complex_add(inst->mid_res_[0][k], inst->mid_res_[j][k]);}}//continue;for (int k = inst->start_; k < inst->end_; k++) {inst->mid_res_[0][k].real_ /= inst->num_input_channels_;inst->mid_res_[0][k].imag_ /= inst->num_input_channels_;}float energy = 0.0;for (int k = inst->start_; k < inst->end_; k++) {energy += inst->mid_res_[0][k].real_ * inst->mid_res_[0][k].real_ + inst->mid_res_[0][k].imag_ * inst->mid_res_[0][k].imag_;}//energy *= energy;inst->frame_id_ = inst->frame_id_ % inst->smooth_len_;inst->P_[i][inst->frame_id_] = energy;float smooth_val = 0.0;for (int k = 0; k < inst->smooth_len_; k++) {smooth_val += inst->P_[i][k];}if (i == 0) {max_id = i;max_val = smooth_val;} else {if (smooth_val > max_val) {max_id = i;max_val = smooth_val;}}}inst->frame_id_ += 1; int angle = max_id * inst->step_; return angle;
}

(5)doa-complex.c

/**@author : aflyingwolf*@date   : 2025.3.20*@file   : doa-complex.c* */#include "doa-complex.h"mouse_complex_f mouse_complex_mul(mouse_complex_f a, mouse_complex_f b) {mouse_complex_f c;c.real_ = a.real_ * b.real_ - a.imag_ * b.imag_;c.imag_ = a.real_ * b.imag_ + a.imag_ * b.real_;return c;
}mouse_complex_f mouse_complex_add(mouse_complex_f a, mouse_complex_f b) {mouse_complex_f c;c.real_ = a.real_ + b.real_;c.imag_ = a.imag_ + b.imag_;return c;
}mouse_complex_f mouse_complex_conj(mouse_complex_f a) {mouse_complex_f ret;ret.real_ = a.real_;ret.imag_ = -1 * a.imag_;return ret;
}

(6)doa-matrix.c

/**@author : aflyingwolf*@date   : 2025.3.20*@file   : doa-matrix.c* */#include "doa-matrix.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>void mouse_complex_matrix_init(mouse_complex_matrix_f *mat, size_t row, size_t col) {mat->num_rows_ = row;mat->num_cols_ = col;mat->data_ = (mouse_complex_f*)malloc(row * col * sizeof(mouse_complex_f));memset(mat->data_, 0, row * col * sizeof(mouse_complex_f));mat->elements_ = (mouse_complex_f**)malloc(row * sizeof(mouse_complex_f*));for(int i = 0; i < row; i++) {mat->elements_[i] = &mat->data_[i * col];}
}void mouse_complex_matrix_free(mouse_complex_matrix_f *mat) {if (mat->data_) {free(mat->data_);free(mat->elements_);}
}
void mouse_complex_matrix_reset(mouse_complex_matrix_f *mat, size_t row, size_t col) {if (mat->data_ != NULL) {free(mat->data_);free(mat->elements_);}mouse_complex_matrix_init(mat, row, col);
}void mouse_complex_matrix_copy_from_column(mouse_complex_matrix_f *mat, size_t column_index, mouse_complex_f **src) {for (int i = 0; i < mat->num_cols_; ++i) {mat->data_[i] = src[i][column_index];}
}void mouse_complex_matrix_copy(mouse_complex_matrix_f *mat, mouse_complex_matrix_f *src) {mouse_complex_matrix_reset(mat, src->num_rows_, src->num_cols_);for (int i = 0; i < mat->num_cols_* mat->num_rows_; ++i) {mat->data_[i] = src->data_[i];}
}float mouse_SumAbs(mouse_complex_matrix_f *mat) {float sum_abs = 0.0;mouse_complex_f **mat_els = mat->elements_;for (int i = 0; i < mat->num_rows_; ++i) {for (int j = 0; j < mat->num_cols_; ++j) {sum_abs += sqrt(mat_els[i][j].real_ * mat_els[i][j].real_ + mat_els[i][j].imag_ * mat_els[i][j].imag_);}}return sum_abs;
}float mouse_SumSquares(mouse_complex_matrix_f *mat) {float sum_squares = 0.f;for (int i = 0; i < mat->num_rows_ * mat->num_cols_; i++) {sum_squares += mat->data_[i].real_ * mat->data_[i].real_ + mat->data_[i].imag_ * mat->data_[i].imag_;}return sum_squares;
}mouse_complex_f mouse_ConjugateDotProduct(mouse_complex_matrix_f *lhs, mouse_complex_matrix_f *rhs) {assert(lhs->num_rows_ == 1);assert(rhs->num_rows_ == 1);assert(rhs->num_cols_ == lhs->num_cols_);mouse_complex_f result;result.real_ = 0.0;result.imag_ = 0.0;mouse_complex_f **lhs_elements = lhs->elements_;mouse_complex_f **rhs_elements = rhs->elements_;for (int i = 0; i < lhs->num_cols_; i++) {mouse_complex_f tmp = mouse_complex_mul(mouse_complex_conj(lhs_elements[0][i]), rhs_elements[0][i]);result = mouse_complex_add(result, tmp);}return result;
}float mouse_Norm(mouse_complex_matrix_f *mat, mouse_complex_matrix_f *norm_mat) {mouse_complex_f first_product, second_product;first_product.real_ = 0.0;first_product.imag_ = 0.0;second_product.real_ = 0.0;second_product.imag_ = 0.0;mouse_complex_f **mat_els = mat->elements_;mouse_complex_f **norm_mat_els = norm_mat->elements_;for (int i = 0; i < norm_mat->num_cols_; i++) {for (int j = 0; j < norm_mat->num_cols_; j++) {first_product = mouse_complex_add(first_product, mouse_complex_mul(mouse_complex_conj(norm_mat_els[0][j]), mat_els[j][i]));}second_product = mouse_complex_add(second_product, mouse_complex_mul(first_product, norm_mat_els[0][i]));first_product.real_ = 0.0;first_product.imag_ = 0.0;}float ret = second_product.real_;if (ret < 0.f) {ret = 0.f;}return ret;
}void mouse_complex_matrix_scale(mouse_complex_matrix_f *mat, mouse_complex_f scale) {int size = mat->num_cols_ * mat->num_rows_;for (int i = 0; i < size; i++) {mat->data_[i] = mouse_complex_mul(mat->data_[i], scale);}
}void mouse_TransposedConjugatedProduct(mouse_complex_matrix_f *in, mouse_complex_matrix_f *out) {assert(in->num_rows_ == 1);assert(out->num_rows_ == in->num_cols_);assert(out->num_cols_ == in->num_cols_);mouse_complex_f* in_elements = in->elements_[0];mouse_complex_f** out_elements = out->elements_;for (int i = 0; i < out->num_rows_; ++i) {for (int j = 0; j < out->num_cols_; ++j) {out_elements[i][j] = mouse_complex_mul(in_elements[i], mouse_complex_conj(in_elements[j]));}}
}mouse_complex_f mouse_Trace(mouse_complex_matrix_f *mat) {assert(mat->num_rows_ == mat->num_cols_);mouse_complex_f trace;trace.real_ = 0.0;trace.imag_ = 0.0;for (int i = 0; i < mat->num_rows_; ++i) {trace = mouse_complex_add(trace, mat->elements_[i][i]);}return trace;
}void mouse_Transpose(mouse_complex_matrix_f *in, mouse_complex_matrix_f *out) {for (int i = 0; i < out->num_rows_; ++i) {for (int j = 0; j < out->num_cols_; ++j) {out->elements_[i][j] = in->elements_[j][i];}}
}void mouse_PointwiseConjugate(mouse_complex_matrix_f *mat) {for (int i = 0; i < mat->num_rows_; ++i) {for (int j = 0; j < mat->num_cols_; ++j) {mat->elements_[i][j].imag_ *= -1;}}
}void mouse_ComplexMatrixMultiply(mouse_complex_matrix_f *interf_cov_vector_transposed, mouse_complex_matrix_f *interf_cov_vector, mouse_complex_matrix_f *mat) {for (int row = 0; row < interf_cov_vector_transposed->num_rows_; ++row) {for (int col = 0; col < interf_cov_vector->num_cols_; ++col) {mouse_complex_f cur_element;cur_element.real_ = 0.0;cur_element.imag_ = 0.0;for (int i = 0; i < interf_cov_vector->num_rows_; ++i) {cur_element = mouse_complex_add(cur_element, mouse_complex_mul(interf_cov_vector_transposed->elements_[row][i], interf_cov_vector->elements_[i][col]));}mat->elements_[row][col] = cur_element;}}
}void mouse_ComplexMatrixAdd(mouse_complex_matrix_f *src1, mouse_complex_matrix_f *src2, mouse_complex_matrix_f *mat) {for (size_t i = 0; i < src1->num_cols_ * src1->num_rows_; ++i) {mat->data_[i] = mouse_complex_add(src1->data_[i], src2->data_[i]);}
}

三、系統部署方式

3.1 運行LED控制進程

3.2 運行數據獲取及算法執行進行

四、總結

? ? ? ? 以上基本上完整記錄了整個系統的代碼及部署方式。由于篇幅限制,完整代碼可以進入https://t.zsxq.com/qgmoN?獲取。注意部署時先啟動LED控制程序。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/73589.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/73589.shtml
英文地址,請注明出處:http://en.pswp.cn/web/73589.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在linux部署網站

在Linux部署網站&#xff0c;需要準備一個純凈的系統 一、系統環境準備 1.設置靜態IP地址 ? 2.關閉默認防火墻 systemctl disable firewalld --now ? 3.配置SSH密鑰登錄 4.yum update -y && reboot # 更新系統內核 5.yum install -y wget curl unzip # 安裝…

Java后端API限流秘籍:高并發的防護傘與實戰指南

目錄導航 ?? ??? 為什么需要API限流??? 主流限流算法大解析????? 阿里巴巴的限流實踐?? 四大黃金定律?? 限流策略組合拳?? 限流場景實戰?? 技術實現方案?? 最佳實踐分享?? 結語與展望?? 推薦閱讀 1. ??? 為什么需要API限流? 在高并發環境中,未…

OpenGL ES 2.0與OpenGL ES 3.1的區別

如果硬件支持且需要更高質量的圖形效果&#xff0c;推薦3.1&#xff1b;如果兼容性和開發簡便更重要&#xff0c;且效果需求不高&#xff0c;2.0更合適。不過現代車載系統可能越來越多支持3.x版本&#xff0c;所以可能傾向于使用3.1&#xff0c;但具體情況還需調查目標平臺的硬…

k8s存儲介紹(五)PV與PVC

在 Kubernetes&#xff08;k8s&#xff09;中&#xff0c;持久化存儲&#xff08;Persistent Storage&#xff09;是一個非常重要的概念&#xff0c;因為 Pod 本身是無狀態的&#xff0c;重啟后會丟失數據。為了支持有狀態應用&#xff0c;Kubernetes 提供了持久化存儲的機制&a…

ORA-00600 [2662]

一、數據庫啟動報ORA-00600[2662] [oraclenode1 ora11g]$ sqlplus / as sysdbaSQL*Plus: Release 11.2.0.3.0 Production on Thu Dec 22 14:37:00 2011Copyright (c) 1982, 2011, Oracle. All rights reserved.Connected to an idle instance.SQL> startup ORACLE instanc…

WebSocket接入SSL證書

目錄 碎碎念解決方法創建 HTTPS WebSocket 服務器創建系統服務啟動服務 碎碎念 在訪問網站時&#xff0c;使用 HTTPS 非常重要。HTTPS 協議不僅可以確保數據傳輸的安全性&#xff0c;還可以防止中間人攻擊和數據篡改等安全問題。任何沒有 SSL 證書的內容都可能會被拒絕訪問。因…

c#在work線程中怎樣更新UI控件

最近筆者調試修改項目&#xff0c;碰到了c#在work線程中怎樣更新UI控件中的場景&#xff0c;簡單總結了下&#xff0c;主要有兩個方法&#xff1a; 方法1&#xff1a;通過System.Windows.Application.Current.Dispatcher.Invoke來更新UI控件 System.Windows.Application.Curre…

?數據結構每日一題day3(順序表)★★★★★

題目描述&#xff1a;順序表L的元素遞增有序排列&#xff0c;設計一個算法在插入元素x后保持該順序表仍然遞增有序排列,插入成功后返回插入元素所在位置,不成功返回-1 算法思想&#xff1a;在遞增有序的順序表中插入元素 x 并保持有序性&#xff0c;步驟如下&#xff1a; 合法…

MyBatis中mapper.xml 的sql映射規則

一、SQL 映射文件核心元素 MyBatis 映射文件的頂級元素&#xff08;按定義順序&#xff09;&#xff1a; cache&#xff1a;命名空間的緩存配置。cache-ref&#xff1a;引用其他命名空間的緩存。resultMap&#xff1a;自定義結果集映射。sql&#xff1a;可重用的 SQL 片段。i…

【計算機網絡】計算機網絡協議、接口與服務全面解析——結合生活化案例與圖文詳解

協議、接口與服務 導讀一、協議1.1 定義1.2 組成 二、接口三、服務3.1 定義3.2 服務與協議的區別3.3 分類3.3.1 面向連接服務于無連接服務3.3.2 可靠服務和不可靠服務3.3.3 有應答服務和無應答服務 結語 導讀 大家好&#xff0c;很高興又和大家見面啦&#xff01;&#xff01;…

Ubuntu服務器中Swapper如何與虛擬內存配合

在Ubuntu服務器中&#xff0c;Swapper和虛擬內存是操作系統中重要的概念&#xff0c;它們共同協作以提高系統的內存管理效率。當物理內存不足時&#xff0c;Swapper會幫助系統將不活躍的數據從內存轉移到磁盤上的交換空間(Swap)&#xff0c;以釋放內存給需要更多資源的進程。下…

SQL Server 中常見的數據類型及其詳細解釋、內存占用和適用場景

以下是 SQL Server 中常見的數據類型及其詳細解釋、內存占用和適用場景&#xff1a; 數據類型類別數據類型解釋內存占用適用場景整數類型bigint用于存儲范圍較大的整數&#xff0c;范圍是 -2^63 (-9,223,372,036,854,775,808) 到 2^63-1 (9,223,372,036,854,775,807)8 字節需要…

vue數字公式篇 Tinymce結合使用(二)

繼上一篇的數字公式 &#xff0c; 這次的功能是將公式能插入編輯器以及修改 1、Tinymce 自定義 LateX 按鈕&#xff0c;打開公式編輯器窗口 LateX.vue window.tinymce.init({...//基礎配置這里我就不寫了setup(ed) {//自定義 LateX 按鈕ed.ui.registry.addButton(LateX, {text:…

python數據增強和轉換

數據增強和轉換 固定轉換隨機轉換概率控制的轉換 固定轉換 邊緣補充像素(Pad)尺寸變換(Resize)中心截取(CenterCrop)頂角及中心截取(FiveCrop)尺灰度變換(GrayScale) 概率控制的轉換 隨機垂直翻轉(RandomVerticalFlip)隨機應用(RandomApply) # -*- coding: utf-8 -*- fro…

Ubuntu下UEFI安全啟動安裝Nvdia驅動

簡介 眾所周知&#xff0c;Ubuntu默認使用Nouveau開源驅動&#xff0c;其性能受限&#xff0c;因此我們需要安裝Nvidia專用驅動。 安裝專用驅動的一般方法非常簡單&#xff0c;只需要sudo ubuntu-drivers devices && sudo ubuntu-drivers autoinstall即可&#xff0c…

05_循環結構三目運算符

目錄 一、雙重for循環 練習 二、break關鍵字 三、continue 關鍵字 練習 四、三元運算 / 三目運算 一、雙重for循環 外層循環 循環一次&#xff0c;&#xff0c;&#xff0c;內層循環 循環一圈&#xff01;&#xff01;&#xff01; 循環里嵌套循環&#xff1a; for(var…

數據結構初階-二叉樹鏈式

目錄 1.概念與結構 2.二叉數鏈式的實現 2.1遍歷規則 2.2申請內存空間 2.3手動構建一棵二叉樹 2.4二叉樹結點的個數 2.5二叉樹葉子結點的個數 2.6二叉樹第K層結點個數 2.7二叉樹的高度 2.8二叉樹中查找值為x的結點 2.9二叉樹的銷毀 3.層序遍歷 3.1概念 3.2層序遍歷…

鴻蒙HarmonyOS NEXT之無感監聽

鴻蒙中存在一些無感監聽&#xff0c;這些監聽經過系統API封裝使用很簡單&#xff0c;但是對實際業務開發中有很重要&#xff0c;例如埋點業務、數據統計、行為上報、切面攔截等。 Navigation的頁面切換 在鴻蒙中Navigation被用來作為路由棧進行頁面跳轉&#xff0c;如果你想知…

批量處理word里面表格的空白行

1&#xff0c;隨便打開一個word文檔。 2&#xff0c;按下Alt F11 VBA編輯器,在左側的「工程資源管理器」窗口中找到Normal 項目,右鍵選擇插入->模塊。 彈出一下彈窗 3&#xff0c;輸入一下代碼 代碼&#xff1a; Sub RemoveEmptyTableRows()Dim tbl As TableDim row As R…

3ds Max 2026 新功能全面解析

一、視口性能與交互體驗升級 1. Hydra 2.0 視口渲染引擎 3ds Max 2026 引入了 Hydra 2.0&#xff0c;大幅優化了視口渲染性能&#xff0c;尤其是在處理復雜場景和高質量實時預覽時&#xff0c;流暢度提升顯著。 支持USD&#xff08;通用場景描述&#xff09;格式&#xff0c…