常见算法——自相关的含义及Python、C实现

news2024/9/21 2:34:43

常见算法——自相关的含义及C实现

  • 一、概念
    • 1. 自相关概念
    • 2. 滞后期
      • 示例说明:
  • 二、自相关的计算步骤:
    • 1. 确定滞后期 (Lag):
    • 2. 计算平均值:
    • 3. 计算自相关:
  • 三、示例 Python自相关计算
    • 1. 代码
    • 2. 运行结果
  • 四、C语言实现自相关算法
    • 1. 代码
    • 2. 运行结果:
    • 3. 优化
    • 4. 检测规律波动

在这里插入图片描述

一、概念

1. 自相关概念

自相关(Autocorrelation)计算是一种用于分析时间序列数据中的模式和周期性的方法。它通过计算当前序列和其自身在不同滞后时间上的相关性,以找出数据是否在某个时间间隔内呈现重复的周期性行为。

如果自相关值较高,说明数据在这些滞后时间点上有相似的变化趋势,可能存在周期性。
如果自相关值较低,说明数据在这些滞后点之间没有显著的相关性。

简单例子:假设我们有一组表示水位的时间序列数据。如果水位是周期性变化的,那么当前时刻的水位值与前几个时刻的水位值会有某种关联,这种关联就可以通过自相关来捕捉。

2. 滞后期

滞后期(lag) 是指在计算自相关时,当前数据序列与它自身的一个滞后版本进行比较的时间差。滞后期代表两个序列之间的位移。具体来说,滞后期为 lag 的自相关计算的是数据序列中每个点与其前 lag 个数据点的相似性。

滞后期的选择通常根据数据的周期性特征来决定。例如,若我们怀疑数据有周期性波动(如正弦波),我们会尝试多个滞后期,看看在哪个滞后期的自相关值最大,进而推测数据的周期。

在常见的分析中,滞后期可能从 1 开始增加,直到找到显著的自相关值或达到数据长度的一半。

示例说明:

假设有一组有规律变化的水位数据:

waterLevel = {10, 12, 14, 16, 18, 16, 14, 12, 10, 8, 6, 8, 10, 12, 14, 16, 18, 16, 14, 12}

这种数据呈现出周期为 10 的波动。当滞后期为 10 时,自相关值会非常高,因为第 i 个数据和第 i-10 个数据会很相似。
在这里插入图片描述

二、自相关的计算步骤:

1. 确定滞后期 (Lag):

自相关的滞后期是指数据点之间的间隔。举例来说,如果滞后期为 3,则我们将当前水位数据与 3 个时间步长前的水位数据进行比较。

2. 计算平均值:

在计算自相关时,通常需要减去数据的均值,来去除掉整体趋势的影响,关注数据的波动。

3. 计算自相关:

在不同的滞后期,计算当前数据和滞后数据的相关性。自相关值的范围在 -1 到 1 之间:

  • 1 表示完美的正相关(完全同步)。
  • -1 表示完全的负相关(反向同步)。
  • 0 表示没有相关性。

三、示例 Python自相关计算

本示例将使用Python生成 1000*10 个数据点,数据点呈正弦分布,但加入了随机参数。
然后程序计算在lag=994的时候自相关度;
最后程序分别计算了200-1000的时候自相关度变化趋势,以方便找出自相关度最大的时候的lag值。

1. 代码

这些点略呈正弦规律,但添加大量噪声:

import numpy as np
import matplotlib.pyplot as plt
from scipy import signal

# 模拟生成 1000*10 的水位数据 (略有规律 + 随机波动 + 周期噪声)
def generate_data(num_points=10000):
    waterLevelData = []
    base_frequency = 2 * np.pi / 1000  # 基础周期
    base_water_level = 27.5  # 基础水位
    amplitude = 12.5  # 振幅
    for i in range(num_points):
        # 每个点的周期有小幅度的随机波动
        noisy_frequency = base_frequency * (1 + np.random.normal(0, 0.01))  # 1% 随机噪声
        water_level = base_water_level + amplitude * np.sin(noisy_frequency * i) + np.random.normal(0, 1)  # 随机波动的水位值
        waterLevelData.append(water_level)
    return waterLevelData

# 绘制水位波形图
def plot_waveform(waterLevelData):
    time = np.arange(0, len(waterLevelData))

    # 创建图形和轴
    plt.figure(figsize=(15, 6))

    # 绘制水位随时间变化的曲线
    plt.plot(time, waterLevelData, label="Water Level", color='blue', marker=None, linewidth=0.5)

    # 添加图形细节
    plt.title("Water Level Over Time with Random Fluctuations and Noisy Periodicity")
    plt.xlabel("Time")
    plt.ylabel("Water Level")
    plt.legend()

    # 显示图形
    plt.grid(True)
    plt.show()

def autocorrelation(data, lag=1):
    n = len(data)
    mean = np.mean(data)
    var = np.var(data)
    data = np.array(data)

    # Compute autocorrelation
    x = data[:-lag]
    y = data[lag:]
    autocorr = np.correlate(x - mean, y - mean, mode='valid') / ((n - lag) * var)
    return autocorr[0]

def plot_autocorrelation(data, min_lag, max_lag):
    autocorrs = [autocorrelation(data, lag) for lag in range(min_lag, max_lag+1)]

    plt.figure(figsize=(10, 5))
    plt.stem(range(min_lag, max_lag+1), autocorrs, use_line_collection=True)
    plt.xlabel('Lag')
    plt.ylabel('Autocorrelation')
    plt.title('Autocorrelation function (ACF)')
    plt.grid(True)
    plt.show()

def resample_data(data, num_points):
    resampled_data = signal.resample(data, num_points)
    return resampled_data

def find_max_autocorrelation_lag_and_value(data, min_lag, max_lag):
    autocorrs = [autocorrelation(data, lag) for lag in range(min_lag, max_lag+1)]
    max_lag = np.argmax(autocorrs) + min_lag
    max_value = np.max(autocorrs)
    return max_lag, max_value

# 主函数
if __name__ == "__main__":
    waterLevelData = generate_data()
    plot_waveform(waterLevelData)

    # 计算指定lag的自相关性
    autocorr = autocorrelation(waterLevelData, 994)
    print("Autocorrelation: ", autocorr)

    # 绘制自相关性图
    max_lag = 1000
    min_lag = 200
    plot_autocorrelation(waterLevelData, min_lag, max_lag)

    # 找到最大自相关性的lag和值
    max_autocorr_lag, max_autocorr_value = find_max_autocorrelation_lag_and_value(waterLevelData, min_lag, max_lag)
    print("Lag with maximum autocorrelation: ", max_autocorr_lag)
    print("Maximum autocorrelation: ", max_autocorr_value)

2. 运行结果

原始数据图形:
在这里插入图片描述
运行结果:
Autocorrelation: 0.8718133244362108
Lag with maximum autocorrelation: 1000
Maximum autocorrelation: 0.8790579058186793
相关度趋势:
在这里插入图片描述
当数据周期比较大时,使用较小的lag将可能计算出错误的自相关度。本示例中数据周期近1000,查找最佳lag时不能从1开始找。

四、C语言实现自相关算法

1. 代码

下面将实现一个功能,用于检测传入的水位数据是否呈现规律变化。每次传入一个新的水位数据,缓存在一个固定大小的环形缓冲区。当缓冲区满了以后,开始计算自相关。
每次计算自相关可以检测自相关值是否显示出明显的周期性。如果自相关值较高,则输出对应位置索引和水位值,及自相关值。
输入数据模拟的是一段无规律值、一段有规律值、再来一段无规律值、一段固定值,波形如下所示:
在这里插入图片描述

代码:

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

#define bufferSize 2000      // 定义水位记录缓冲区大小
#define autocorrThreshold 0.9  // 自相关阈值,用于判断是否有规律

int waterLevelBuffer[bufferSize];  // 水位数据缓冲区
int currentIndex = 0;              // 当前缓冲区索引
int dataCount = 0;                 // 当前已传入的数据计数

// 计算滞后期为 lag 的自相关值
float computeAutocorrelation(int lag) {
    float mean = 0;
    float autocorrelation = 0;
    float variance = 0;

    // 计算水位数据的平均值
    for (int i = 0; i < bufferSize; i++) {
        mean += waterLevelBuffer[i];
    }
    mean /= bufferSize;

    // 计算方差(归一化因子)
    for (int i = 0; i < bufferSize; i++) {
        variance += (waterLevelBuffer[i] - mean) * (waterLevelBuffer[i] - mean);
    }

    // 计算滞后期为 lag 的自相关值
    for (int i = 0; i < bufferSize; i++) {
        int index1 = (currentIndex + i) % bufferSize;
        int index2 = (currentIndex + i + lag) % bufferSize;
        autocorrelation += (waterLevelBuffer[index1] - mean) * (waterLevelBuffer[index2] - mean);
    }

    // 返回归一化后的自相关值
    return autocorrelation / variance;
}

// 检查水位数据是否有规律,返回自相关度
float checkForPattern() {
    if (dataCount < bufferSize) {
        // 缓冲区还未满,无法计算自相关
        return 0;
    }

    // 检测滞后期为 500 到 1000 的自相关
    for (int lag = 900; lag <= 1100; lag++) {
        float autocorr = computeAutocorrelation(lag);
        if (autocorr > autocorrThreshold) {
           // printf("detected at lag = %d, Autocorrelation = %.4f\n", lag, autocorr);
            return autocorr;
        }
    }

    // 没有检测到规律,继续收集数据
    return 0;
}

// 模拟传入一个水位数据,返回自相关度
float addWaterLevelData(int newWaterLevel) {
    // 将新的水位数据存入缓冲区
    waterLevelBuffer[currentIndex] = newWaterLevel;
    currentIndex = (currentIndex + 1) % bufferSize;
    dataCount++;

    // 检查当前缓冲区数据是否有规律
    return checkForPattern();
}

// 模拟生成有规律变化的水位数据
int generateRegularWaterLevel(int step) {
    float noise = ((float)rand() / RAND_MAX) * 8 - 4;  // Generate a random float between -2 and 2
    return 25 + 12.5 * sin(2 * M_PI * step / 1000)+noise;  // 周期为 1000 的正弦波
}

// 模拟生成无规律变化的水位数据
int generateIrregularWaterLevel() {
    return 25 + rand() % 5;  // 随机生成0到20的水位
}

int main() {
    // 模拟生成1000*12个水位数据,逐个传入检测
    printf("Simulating 12000 water level data points...\n");

    for (int i = 0; i < 1000*12; i++) {
        // 模拟产生数据,可以根据需要生成有规律或无规律的数据
        int waterLevel;
        if (i > 1000*3 && i<1000*6) {
            // 后5000个数据是有规律的
            waterLevel = generateRegularWaterLevel(i);
        } else if(i>8000){
            waterLevel=25;
        }else{
            // 前5000个数据是无规律的
            waterLevel = generateIrregularWaterLevel();
        }

        // 传入数据
        float val = addWaterLevelData(waterLevel);
        if(val>0) {
            // 打印当前传入的水位数据
            printf("Water level at step %d: %d, autoCorrelation=%f\n", i + 1, waterLevel, val);
        }
//        printf(",%d",waterLevel);
    }

    return 0;
}

2. 运行结果:

Simulating 10000 water level data points...
Water level at step 4880: 14, autoCorrelation=0.900089
Water level at step 4881: 17, autoCorrelation=0.901121
Water level at step 4882: 14, autoCorrelation=0.901935
Water level at step 4883: 19, autoCorrelation=0.900232
Water level at step 4884: 14, autoCorrelation=0.900028
...
Water level at step 6193: 26, autoCorrelation=0.900189
Water level at step 6194: 26, autoCorrelation=0.901144
Water level at step 6195: 28, autoCorrelation=0.900636
Water level at step 6196: 28, autoCorrelation=0.900139

3. 优化

在新的数据进来时,不需要对所有数据计算均值和方差,只需要对新数据进行计算,下面是改进的算法:

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

#define bufferSize 2000      // 定义水位记录缓冲区大小
#define autocorrThreshold 0.9  // 自相关阈值,用于判断是否有规律

int waterLevelBuffer[bufferSize];  // 水位数据缓冲区
int currentIndex = 0;              // 当前缓冲区索引
int dataCount = 0;                 // 当前已传入的数据计数
float mean = 0;
float variance = 0;
// 计算滞后期为 lag 的自相关值
float computeAutocorrelation(int lag) {
    float autocorrelation = 0;
    if(lag>bufferSize){
        return 0;
    }

    // 计算滞后期为 lag 的自相关值
    for (int i = 0; i < bufferSize; i++) {
        int index1 = (currentIndex + i) % bufferSize;
        int index2 = (currentIndex + i + lag) % bufferSize;
        autocorrelation += (waterLevelBuffer[index1] - mean) * (waterLevelBuffer[index2] - mean);
    }

    // 返回归一化后的自相关值
    return autocorrelation / variance;
}

// 检查水位数据是否有规律,返回自相关度
float checkForPattern() {
    if (dataCount < bufferSize) {
        // 缓冲区还未满,无法计算自相关
        return 0;
    }

    // 检测滞后期为 500 到 1000 的自相关
    for (int lag = 900; lag <= 1100; lag++) {
        float autocorr = computeAutocorrelation(lag);
        if (autocorr > autocorrThreshold) {
            return autocorr;
        }
    }

    // 没有检测到规律,继续收集数据
    return 0;
}

// 模拟传入一个水位数据,返回自相关度
float addWaterLevelData(int newWaterLevel) {
    int oldWaterLevel = waterLevelBuffer[currentIndex];
    // 更新均值和方差
    if(dataCount ==0){
        mean = newWaterLevel;
        variance = 0;
    }
    else if (dataCount < bufferSize) {
        float oldMean = mean;
        mean = (mean * dataCount + newWaterLevel) / (dataCount+1);
        variance = variance + (newWaterLevel - oldMean) * (newWaterLevel - mean);
    } else {
        mean = mean + (newWaterLevel - oldWaterLevel) / bufferSize;
        variance = variance - (oldWaterLevel - mean) * (oldWaterLevel - mean)
                + (newWaterLevel - mean) * (newWaterLevel - mean);
    }
    // 将新的水位数据存入缓冲区
    waterLevelBuffer[currentIndex] = newWaterLevel;
    if (dataCount < bufferSize-1) {
        currentIndex++;
    } else {
        currentIndex = (currentIndex + 1) % bufferSize;
    }
    dataCount++;

    // 检查当前缓冲区数据是否有规律
    return checkForPattern();
}

// 模拟生成有规律变化的水位数据
int generateRegularWaterLevel(int step) {
    float noise = ((float)rand() / RAND_MAX) * 8 - 4;  // Generate a random float between -2 and 2
    return 25 + 12.5 * sin(2 * M_PI * step / 1000)+noise;  // 周期为 1000 的正弦波
}

// 模拟生成无规律变化的水位数据
int generateIrregularWaterLevel() {
    return 25 + rand() % 5;  // 随机生成0到20的水位
}

int main() {
    // 模拟生成1000*12个水位数据,逐个传入检测
    printf("Simulating 12000 water level data points...\n");

    for (int i = 0; i < 1000*12; i++) {
        // 模拟产生数据,可以根据需要生成有规律或无规律的数据
        int waterLevel;
        if (i > 1000*3 && i<1000*6) {
            // 后5000个数据是有规律的
            waterLevel = generateRegularWaterLevel(i);
        } else if(i>8000){
            waterLevel=25;
        }else{
            // 前5000个数据是无规律的
            waterLevel = generateIrregularWaterLevel();
        }

        // 传入数据
        float val = addWaterLevelData(waterLevel);
        if(val>0) {
            // 打印当前传入的水位数据
            printf("Water level at step %d: %d, autoCorrelation=%f\n", i + 1, waterLevel, val);
        }
//        printf(",%d",waterLevel);
    }

    return 0;
}

4. 检测规律波动

上面的算法里,在最后一段数据是常数不变时,算法仍会返回高相关值。有时候我们希望检测到水位发生了规则变化,而不是仅高相关值。
下面采用局部标准差的滑动窗口检测,即通过检测一段数据中的局部波动来判断数据是否有足够的变化。方法是计算水位数据的局部标准差,如果局部标准差过小,说明数据可能是常值或变化不大,从而跳过自相关计算。

另外下面代码实现连续100次检测到自相关值达到目标值,则输出检测成功。

标准差计算的是方差的平方根

改进后的代码:

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

#define bufferSize 2000             // 定义水位记录缓冲区大小
#define autocorrThreshold 0.9       // 自相关阈值,用于判断是否有规律
#define alertThreshold 100          // 连续达到自相关阈值的次数,用于报警
#define windowSize 100              // 用于计算局部标准差的滑动窗口大小

int waterLevelBuffer[bufferSize];   // 水位数据缓冲区
int currentIndex = 0;               // 当前缓冲区索引
int dataCount = 0;                  // 当前已传入的数据计数
int alertCounter = 0;               // 记录连续达到自相关阈值的次数
float mean = 0;
float variance = 0;
int patternDetected = 0;            // 标志,是否检测到规律变化

// 计算滞后期为 lag 的自相关值
float computeAutocorrelation(int lag) {
    // 检查方差是否接近0。如果是,那么就直接返回0,表示数据没有变化,自相关值没有意义。
    if (lag >= bufferSize || variance < 1e-6) {  // 检查滞后期和方差
        return 0;
    }

    float autocorrelation = 0;

    // 计算滞后期为 lag 的自相关值
    for (int i = 0; i < bufferSize; i++) {
        int index1 = (currentIndex + i) % bufferSize;
        int index2 = (currentIndex + i + lag) % bufferSize;
        autocorrelation += ((float)waterLevelBuffer[index1] - mean) * ((float)waterLevelBuffer[index2] - mean);
    }

    // 返回归一化后的自相关值
    return autocorrelation / variance;
}

// 计算滑动窗口内的局部标准差
float computeLocalStandardDeviation() {
    if (dataCount < windowSize) {
        return 0;  // 数据不足时无法计算局部标准差
    }

    // 计算窗口内的均值
    float localMean = 0;
    for (int i = 0; i < windowSize; i++) {
        int index = (currentIndex + i) % bufferSize;
        localMean += (float)waterLevelBuffer[index];
    }
    localMean /= windowSize;

    // 计算窗口内的标准差
    float localVariance = 0;
    for (int i = 0; i < windowSize; i++) {
        int index = (currentIndex + i) % bufferSize;
        localVariance += (float)pow((float)waterLevelBuffer[index] - localMean, 2);
    }
    localVariance /= windowSize;

    return sqrt(localVariance);  // 返回局部标准差
}

// 检查水位数据是否有规律,返回自相关度
float checkForPattern() {
    if (dataCount < bufferSize) {
        // 缓冲区还未满,无法计算自相关
        return 0;
    }

    // 计算局部标准差,确保数据有足够的波动
    float localStdDev = computeLocalStandardDeviation();
    if (localStdDev < 1.0) {
        return 0;  // 数据变化幅度过小,跳过自相关计算
    }

    // 检测滞后期为 900 到 1100 的自相关
    for (int lag = 900; lag <= 1100; lag++) {
        float autocorr = computeAutocorrelation(lag);
        if (autocorr > autocorrThreshold) {
            return autocorr;
        }
    }

    // 没有检测到规律,继续收集数据
    return 0;
}

// 模拟传入一个水位数据,返回自相关度
float addWaterLevelData(int newWaterLevel) {
    int oldWaterLevel = waterLevelBuffer[currentIndex];
    // 更新均值和方差
    if (dataCount == 0) {
        mean = (float)newWaterLevel;
        variance = 0;
    } else if (dataCount < bufferSize) {
        float oldMean = mean;
        mean = (mean * (float)dataCount + (float)newWaterLevel) / ((float)dataCount + 1);
        variance = variance + ((float)newWaterLevel - oldMean) * ((float)newWaterLevel - mean);
    } else {
        mean = mean + (float)(newWaterLevel - oldWaterLevel) / bufferSize;
        variance = variance - ((float)oldWaterLevel - mean) * ((float)oldWaterLevel - mean)
                   + ((float)newWaterLevel - mean) * ((float)newWaterLevel - mean);
    }

    // 将新的水位数据存入缓冲区
    waterLevelBuffer[currentIndex] = newWaterLevel;
    currentIndex = (currentIndex + 1) % bufferSize;
    dataCount++;

    // 检查当前缓冲区数据是否有规律
    return checkForPattern();
}

// 模拟生成有规律变化的水位数据
int generateRegularWaterLevel(int step) {
    float noise = (float)(rand() / (float)RAND_MAX) * 8 - 4;  // 生成随机噪声
    return (int)(25 + 12.5 * sin(2 * M_PI * step / 1000) + noise);  // 周期为 1000 的正弦波
}

// 模拟生成无规律变化的水位数据
int generateIrregularWaterLevel() {
    return (int)(25 + rand() % 5);  // 随机生成 0 到 5 的水位
}

int main() {
    // 模拟生成 12000 个水位数据,逐个传入检测
    printf("模拟生成 12000 水位数据...\n");

    for (int i = 0; i < 12000; i++) {
        // 模拟产生数据,可以根据需要生成有规律或无规律的数据
        int waterLevel;
        if (i > 3000 && i < 6000) {
            // 中间这段数据是有规律的
            waterLevel = generateRegularWaterLevel(i);
        } else if (i > 8000) {
            waterLevel = 25;  // 这一段数据是常值
        } else {
            // 其余部分数据是无规律的
            waterLevel = generateIrregularWaterLevel();
        }

        // 传入数据
        float val = addWaterLevelData(waterLevel);

        // 检查自相关是否超过阈值,并进行计数
        if (val > autocorrThreshold) {
            alertCounter++;
            if (alertCounter >= alertThreshold && !patternDetected) {
                printf("第 %d 步连续 %d 次检测到自相关值超阈值!\n", i + 1, alertThreshold);
                patternDetected = 1;  // 标志已检测到规律
            }
        } else {
            alertCounter = 0;  // 自相关值未达到阈值时,重置计数器
        }
    }

    return 0;
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2140432.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

yjs06——numpy的介绍与优势(1)

1.numpy是什么&#xff1f; numpy是python的一个科学计算库&#xff0c;用于快速处理 任意维度的数据&#xff1b; numpy的存储单元/基本数据类型是 ndarray&#xff08;多维数组&#xff09; 2.多维数组的建立&#xff1a; import numpy as np np.array([ [1,2,3], [4,5,6…

C++ | Leetcode C++题解之第406题根据身高重建队列

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {sort(people.begin(), people.end(), [](const vector<int>& u, const vector<int>& v) …

IV 无规矩不成方圆,区块链的“规矩”是怎么起作用的?

大家好啊&#xff0c;我是豆小匠。 通过前面几期&#xff0c;我们知道区块链是一种非中心化的解决方案&#xff0c;没有“中央处理器”。 那么&#xff0c;区块链中的各种操作&#xff0c;比如转账、状态记录等规则是怎么定义&#xff0c;又是怎么起作用的呢&#xff1f; 本…

QT--connect的使用

在qt里面我们可以用connect将信号与槽函数连接器起来&#xff0c;而connect是一个常用的函数&#xff0c;用法也非常简单。 来看一个非常简单的栗子 Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);qpbnew QPushButton(this)…

go语言中的数组指针和指针数组的区别详解

1.介绍 大家知道C语言之所以强大&#xff0c;就是因为c语言支持指针&#xff0c;而且权限特别大&#xff0c;c语言可以对计算机中任何内存的指针进行操作&#xff0c;这样自然而然也会带来一些不安全的因素&#xff0c;所以在golang中&#xff0c;「取消了对指针的一些偏移&…

清理Go/Rust编译时产生的缓存

Go Mac 1T的磁盘频频空间高级&#xff0c;发现是/Users/yourname/Library/Caches/go-build 目录占用了大量空间。 此目录保存来自 Go 构建系统的缓存构建工件。 如果目录太大&#xff0c;请运行go clean -cache。 运行go clean -fuzzcache以删除模糊缓存。 当时直接手工清理了…

C++——多线程编程(从入门到放弃)

进程&#xff1a;运行中的程序 线程&#xff1a;进程中的进程 线程的最大数量取决于CPU的核心数 一、将两个函数添加到不同线程中 demo&#xff1a;两个函数test01()和test02()&#xff0c;实现将用户输入的参数进行打印输出1000次 将这两个函数均放到独立的线程t1和t2中&…

STM32 的 CAN 通讯全攻略

目录 一、CAN 通讯概述 二、 CAN 通讯原理 1.ISO11898 标准下的物理层特征 2.CAN 协议的帧类型 3. 总线仲裁介绍 4.位时序 5.STM32 CAN 控制器简介 6.标识符筛选器 三、软件设计 1.发送流程 1.1初始化 CAN 控制器 1.2准备发送数据 1.3 将数据填充到发送缓冲区 1.4…

初始c++的继承

概念&#xff1a; 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特性的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。继承呈现了面向对象程序设计的层次结构&#xff0c…

Java高级Day43-类加载

117.类加载 静态和动态加载 反射机制是java实现动态语言的关键&#xff0c;也就是通过反射实现类动态加载 静态加载&#xff1a;编译时加载相关的类&#xff0c;如果没有则报错&#xff0c;依赖性太强 动态加载&#xff1a;运行时加载需要的类&#xff0c;如果运行时不用该类…

集群聊天服务器项目【C++】(五)网络模块和业务模块

经过前面介绍相关的库和工具&#xff0c;比如Json、CMake、muduo等&#xff0c;我们可以开始编写本项目的代码了。 1.项目目录创建 一般一个项目由以下结构组成&#xff1a; bin文件夹存放&#xff1a;可执行程序build文件夹存放&#xff1a;编译过程中的临时文件include文…

消失的数去哪里了

大家好&#xff0c;我是大圣&#xff0c;最近消失了很长一段时间了&#xff0c;之前答应粉丝要更新的文章也没有按时更新。其实我这段时间去闭关修炼去了&#xff0c;现在满血归来啦&#xff0c;之前答应粉丝的文章都会陆续发出来的。 消失的 Count 去哪了 今天给大家分享一个…

BolckingQueue

队列 队列的特点先进先出&#xff08;FIFO&#xff09;。 如图&#xff1a; 进入队列的顺序是1&#xff0c;2&#xff0c;3&#xff0c;那么出队列的顺序只能是1&#xff0c;2&#xff0c;3&#xff0c;不可能是其他顺序&#xff0c;这是由队列的特点保证的。 保存数据的基本…

彻底理解浅拷贝和深拷贝

目录 浅拷贝实现 深拷贝实现自己手写 浅拷贝 浅拷贝是指创建一个新对象&#xff0c;这个对象具有原对象属性的精确副本 基本数据类型&#xff08;如字符串、数字等&#xff09;&#xff0c;在浅拷贝过程中它们是通过值传递的&#xff0c;而不是引用传递&#xff0c;修改值并不…

基于yolov8的茶叶病害检测系统python源码+onnx模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv8的茶叶病害检测系统&#xff0c;是利用深度学习技术&#xff0c;特别是YOLOv8这一先进的目标检测算法&#xff0c;来精准识别和监测茶叶生长过程中出现的各种病害。该系统通过无人机、地面机器人或固定摄像头等设备&#xff0c;定期采集茶园的高分辨率…

力扣刷题(6)

两数之和 II - 输入有序数组 两数之和 II - 输入有序数组-力扣 思路&#xff1a; 因为该数组是非递减顺序排列&#xff0c;因此可以设两个左右下标当左右下标的数相加大于target时&#xff0c;则表示右下标的数字过大&#xff0c;因此将右下标 - -当左右下标的数相加小于targ…

??Ansible——ad-hoc

文章目录 一、ad-hoc介绍二、ad-hoc的使用1、语法2、ad-hoc常用模块1&#xff09;shell模块2&#xff09;command模块3&#xff09;script模块4&#xff09;file模块5&#xff09;copy模块6&#xff09;yum模块7&#xff09;yum-repository模块8&#xff09;service模块9&#…

优化算法(一)—遗传算法(Genetic Algorithm)附MATLAB程序

遗传算法&#xff08;Genetic Algorithm, GA&#xff09;是一种启发式搜索算法&#xff0c;用于寻找复杂优化问题的近似解。它模拟了自然选择和遗传学中的进化过程&#xff0c;主要用于解决那些传统算法难以处理的问题。 遗传算法的基本步骤&#xff1a; 初始化种群&#xff0…

【GO语言】Go语言详解与应用场景分析,与Java的对比及优缺点

Go is an open source programming language that makes it easy to build simple, reliable, and efficient software. Go是一种开源编程语言&#xff0c;可以轻松构建简单、可靠和高效的软件。 文章目录 一、引言二、Go语言详解1. 简史2. 特点3. 核心库 三、应用场景四、与Ja…

comfyui中,sam detector与yoloworld图像分割算法测试以及影响

&#x1f356;背景 图像处理中&#xff0c;经常会用到图像分割&#xff0c;在默认的comfyui图像加载中就有一个sam detector的功能&#xff0c;yoloworld是前一段时间公开的一个更强大的图像分割算法&#xff0c;那么这两个差别大吗&#xff1f;在实际应用中有什么区别吗&…