третья часть, плюс добавил программу для анализа результатов из курского проекта. правда она что-то не то показывает.... но разберусь завтра
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.28)
|
||||
project(tests)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
add_executable(tests main.cpp computing.cpp computing.h)
|
||||
@@ -0,0 +1,114 @@
|
||||
#include <cstring>
|
||||
#include "computing.h"
|
||||
|
||||
uint8_t ExtAdcBuffer[EXT_ADC_BUFFER_SIZE];
|
||||
|
||||
|
||||
bool computeAdcResults(uint32_t &freq, double &litude, double &dc) {
|
||||
// Краевые значения не обрабатываем
|
||||
#define edge1 32
|
||||
|
||||
// Частота АЦП
|
||||
const double Fd = (168.0f / 9.0f) * 1e6f; // Частота дискретизации в герцах
|
||||
|
||||
// uint8_t ExtAdcBuffer[EXT_ADC_BUFFER_SIZE];
|
||||
|
||||
// Применем медианный фильтр
|
||||
// MedianFilter3();
|
||||
|
||||
// Применим фильтр скользящего среднеего
|
||||
// MovAvgFilter5();
|
||||
|
||||
// **************************************************************************
|
||||
// Оценка размаха. Построим гистограмму
|
||||
// знаем, что разрядность АЦП 8 бит - 256 значений
|
||||
|
||||
// Обнуляем вспомогательный массив
|
||||
int gg[256];
|
||||
memset(gg, 0, sizeof(gg));
|
||||
|
||||
// Формируем гистограмму
|
||||
for (uint16_t i = edge1; i < EXT_ADC_BUFFER_SIZE - edge1; i++)
|
||||
gg[ExtAdcBuffer[i]]++;
|
||||
|
||||
// Оцениваем пики гистограммы
|
||||
|
||||
int xm = 0;
|
||||
uint8_t km1 = 0;
|
||||
uint8_t km2 = 0;
|
||||
for (uint16_t i = 0; i < 120; i++) {
|
||||
if (xm < gg[i]) {
|
||||
xm = gg[i];
|
||||
km1 = i;
|
||||
}
|
||||
}
|
||||
|
||||
xm = 0;
|
||||
for (uint16_t i = 134; i <= 0xFF; i++) {
|
||||
if (xm < gg[i]) {
|
||||
xm = gg[i];
|
||||
km2 = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Определяем оценку напряжения в милливольтах, применительно к размаху АЦП
|
||||
amplitude = (double) (km2 - km1) / 256.0;
|
||||
amplitude *= 2.6048450117218023; // NOTE: магический кофицент для схемы
|
||||
|
||||
// расчет постоянной составляющей
|
||||
dc = ((((double) km1 + (double) km2) / 2.0f) / 256.0f * 1000.0f) + 2000.0f;
|
||||
// y = 2 + x
|
||||
|
||||
|
||||
// **************************************************************************
|
||||
// Оцениваем частоту
|
||||
// Считаем, что 128й уровень находится ровно посередине
|
||||
|
||||
const uint16_t z = 8; // Защитный интервал
|
||||
uint32_t xk1 = 0;
|
||||
uint32_t xk2 = 0;
|
||||
uint32_t xsum = 0;
|
||||
uint32_t xnum = 0;
|
||||
|
||||
uint32_t i = edge1;
|
||||
// ищем переходы через 128
|
||||
while ((i < EXT_ADC_BUFFER_SIZE - edge1) && (ExtAdcBuffer[i] > 128))
|
||||
i++;
|
||||
i = i + z;
|
||||
while ((i < EXT_ADC_BUFFER_SIZE - edge1) && (ExtAdcBuffer[i] < 128))
|
||||
i++;
|
||||
xk1 = i;
|
||||
while ((i < EXT_ADC_BUFFER_SIZE - edge1) && (ExtAdcBuffer[i] > 128))
|
||||
i++;
|
||||
i = i + z;
|
||||
while ((i < EXT_ADC_BUFFER_SIZE - edge1) && (ExtAdcBuffer[i] < 128))
|
||||
i++;
|
||||
xk2 = i;
|
||||
i = i + i;
|
||||
xsum = xk2 - xk1;
|
||||
xnum = 1;
|
||||
|
||||
// Находим много периодов
|
||||
while (i < EXT_ADC_BUFFER_SIZE - edge1) {
|
||||
while ((i < EXT_ADC_BUFFER_SIZE - edge1) && (ExtAdcBuffer[i] > 128))
|
||||
i++;
|
||||
i = i + z;
|
||||
while ((i < EXT_ADC_BUFFER_SIZE - edge1) && (ExtAdcBuffer[i] < 128))
|
||||
i++;
|
||||
if (i < EXT_ADC_BUFFER_SIZE - edge1) {
|
||||
xsum = xsum + (i - xk2);
|
||||
xnum++;
|
||||
xk2 = i;
|
||||
}
|
||||
i = i + z;
|
||||
}
|
||||
// Оценка частоты в герцах
|
||||
freq = (uint32_t) (Fd / (double) xsum * (double) xnum);
|
||||
|
||||
// Посмотрим, если есть переполнение АЦП в одну или в друнгую сторону, то
|
||||
// выдадим ошибку
|
||||
if ((km1 == 0) | (km2 == 255))
|
||||
return (false);
|
||||
else
|
||||
return (true);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef KURSK_F407_SLAVES_H
|
||||
#define KURSK_F407_SLAVES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
// 64к = 0x10000, words 16к = 0x4000
|
||||
// 32к = 0x8000, words 16к = 0x2000
|
||||
|
||||
/**
|
||||
* Размер буфера внешнего ADC
|
||||
*/
|
||||
#define EXT_ADC_BUFFER_SIZE 0x8000
|
||||
|
||||
|
||||
/**
|
||||
* Буфер, куда попадают данные внешнего ADC.
|
||||
*/
|
||||
extern uint8_t ExtAdcBuffer[EXT_ADC_BUFFER_SIZE];
|
||||
|
||||
/**
|
||||
* Функция, выполняющая расчет частоты и амплитуды на основании данных АЦП.
|
||||
* Определение этой функции можно будет изменить, если это требуется
|
||||
* @param freq частота
|
||||
* @param amplitude амплитуда
|
||||
* @param dc постоянная составляющая
|
||||
* @return true, в случае если в процессе обработки не возникло ошибок, в противном случае false
|
||||
*/
|
||||
bool computeAdcResults(uint32_t &freq, double &litude, double &dc);
|
||||
|
||||
#endif //__cplusplus
|
||||
|
||||
#endif //KURSK_F407_SLAVES_H
|
||||
@@ -0,0 +1,132 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iomanip>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
|
||||
#include "computing.h"
|
||||
|
||||
bool computeAdcResults(uint32_t &freq, double &litude, double &dc);
|
||||
|
||||
struct TestInfo {
|
||||
uint32_t referenceFreqKhz;
|
||||
double referenceAmplitudeMv;
|
||||
std::filesystem::path fileName;
|
||||
};
|
||||
|
||||
std::optional<TestInfo> parseFileName(const std::filesystem::path &path) {
|
||||
static const std::regex re(R"((\d+)\s*khz.*?(\d+)\s*mv)",
|
||||
std::regex::icase);
|
||||
|
||||
std::smatch match;
|
||||
std::string name = path.stem().string();
|
||||
|
||||
if (!std::regex_search(name, match, re))
|
||||
return std::nullopt;
|
||||
|
||||
TestInfo info;
|
||||
info.referenceFreqKhz = std::stoul(match[1].str());
|
||||
info.referenceAmplitudeMv = std::stod(match[2].str());
|
||||
info.fileName = path;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
bool loadSamples(const std::filesystem::path &path, std::vector<uint8_t> &samples) {
|
||||
std::ifstream file(path);
|
||||
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
samples.clear();
|
||||
|
||||
unsigned value;
|
||||
|
||||
while (file >> value) {
|
||||
if (value > 255)
|
||||
return false;
|
||||
samples.push_back(static_cast<uint8_t>(value));
|
||||
}
|
||||
|
||||
return !samples.empty();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
std::cout
|
||||
<< "File\t"
|
||||
<< "Freq_ref_kHz\t"
|
||||
<< "Amp_ref_mV\t"
|
||||
<< "Freq_alg_kHz\t"
|
||||
<< "Amp_alg_mV\t"
|
||||
<< "Freq_abs_err_kHz\t"
|
||||
<< "Freq_rel_err_% \t"
|
||||
<< "Amp_abs_err_mV\t"
|
||||
<< "Amp_rel_err_%"
|
||||
<< '\n';
|
||||
|
||||
for (const auto &entry : fs::directory_iterator("."))
|
||||
{
|
||||
if (!entry.is_regular_file())
|
||||
continue;
|
||||
|
||||
if (entry.path().extension() != ".txt")
|
||||
continue;
|
||||
|
||||
auto info = parseFileName(entry.path());
|
||||
|
||||
if (!info)
|
||||
continue;
|
||||
|
||||
std::vector<uint8_t> samples;
|
||||
|
||||
if (!loadSamples(entry.path(), samples))
|
||||
{
|
||||
std::cerr << "Cannot read " << entry.path() << '\n';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (samples.size() != EXT_ADC_BUFFER_SIZE) {
|
||||
std::cerr << "ERROR: " << entry.path() << " invalid samples count: expect " << EXT_ADC_BUFFER_SIZE << ", got " << samples.size() << '\n';
|
||||
continue;
|
||||
}
|
||||
memcpy(ExtAdcBuffer, samples.data(), samples.size());
|
||||
|
||||
uint32_t freqHz = 0;
|
||||
double amplitude = 0.0;
|
||||
double dc = 0.0;
|
||||
|
||||
if (!computeAdcResults(freqHz, amplitude, dc)) {
|
||||
std::cerr << "Processing failed: " << entry.path() << '\n';
|
||||
continue;
|
||||
}
|
||||
const double freq = static_cast<double>(freqHz) / 1000.0;
|
||||
amplitude = amplitude * 1000.0;
|
||||
|
||||
double freqAbsError = std::abs(static_cast<double>(freq) - info->referenceFreqKhz);
|
||||
double freqRelError = freqAbsError / info->referenceFreqKhz * 100.0;
|
||||
double ampAbsError = std::abs(amplitude - info->referenceAmplitudeMv);
|
||||
double ampRelError = ampAbsError / info->referenceAmplitudeMv * 100.0;
|
||||
|
||||
std::cout
|
||||
<< entry.path().filename().string() << '\t'
|
||||
<< info->referenceFreqKhz << '\t'
|
||||
<< info->referenceAmplitudeMv << '\t'
|
||||
<< freq << '\t'
|
||||
<< std::fixed << std::setprecision(2) << amplitude << '\t'
|
||||
<< freqAbsError << '\t'
|
||||
<< freqRelError << '\t'
|
||||
<< ampAbsError << '\t'
|
||||
<< ampRelError
|
||||
<< '\n';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user