polarimeter_software/User/app/pm_params.c

257 lines
7.1 KiB
C
Raw Normal View History

2025-09-30 02:37:23 +00:00
/*
* @Author: mypx
* @Date: 2025-09-24 11:10:45
* @LastEditTime: 2025-09-24 13:32:18
* @LastEditors: mypx mypx_coder@163.com
* @Description:
*/
#include "pm_params.h"
#include "et_log.h"
static pm_params_t *pm_params = NULL;
/**
* @brief Calculate actual rotation (measured value - zero point)
*
* @param params Pointer to measurement parameters
* @return float Actual rotation value (°)
*/
float pm_calculate_actual_rotation(pm_params_t *params)
{
return params->measured.measured_value - params->measured.zero_point;
}
/**
* @brief Calculate specific rotation
*
* @param params Pointer to measurement parameters
* @return float Specific rotation ([α], °)
*/
float pm_calculate_specific_rotation(pm_params_t *params)
{
float actual_rotation = pm_calculate_actual_rotation(params);
/* Specific rotation formula: [α] = (100 × α) / (L × C)
* L: tube length (dm) from config
* C: concentration (g/100ml) from measured
*/
float L = params->config.tube_length;
float C = params->measured.concentration;
if (L == 0.0f || C == 0.0f)
{
ET_ERR("Error: tube length or concentration must not be zero when calculating specific rotation\n");
return NAN;
}
return (100.0f * actual_rotation) / (L * C);
}
/**
* @brief Calculate concentration
*
* @param params Pointer to measurement parameters
* @return float Concentration (g/100ml)
*/
float pm_calculate_concentration(pm_params_t *params)
{
float actual_rotation = pm_calculate_actual_rotation(params);
/* Concentration formula: C = (100 × α) / (L × [α])
* L: tube length from config
* [α]: specific rotation from measured
*/
float L = params->config.tube_length;
float alpha = params->measured.specific_rotation;
if (L == 0.0f || alpha == 0.0f)
{
ET_ERR("Error: tube length or specific rotation must not be zero when calculating concentration\n");
return NAN;
}
return (100.0f * actual_rotation) / (L * alpha);
}
/**
* @brief Calculate international sugar scale (°Z)
*
* @param params Pointer to measurement parameters
* @return float Sugar scale value (°Z)
*/
float pm_calculate_sugar_scale(pm_params_t *params)
{
float actual_rotation = pm_calculate_actual_rotation(params);
// International sugar scale formula: °Z = α × 2.888
return actual_rotation * 2.888f;
}
/**
* @brief Perform calculation based on selected measurement mode
*
* @param params Pointer to measurement parameters
* @return float Calculation result
*/
float pm_calculate_measurement(pm_params_t *params)
{
switch (params->config.mode)
{
case PM_MEAS_MODE_OPTICAL_ROTATION:
return pm_calculate_actual_rotation(params);
case PM_MEAS_MODE_SPECIFIC_ROTATION:
return pm_calculate_specific_rotation(params);
case PM_MEAS_MODE_CONCENTRATION:
return pm_calculate_concentration(params);
case PM_MEAS_MODE_SUGAR_SCALE:
return pm_calculate_sugar_scale(params);
default:
ET_ERR("Error: invalid measurement mode\n");
return NAN;
}
}
/**
* @brief Get the name of the measurement mode
*
* @param mode Measurement mode
* @return const char* Mode name string
*/
const char *pm_get_mode_name(PM_MeasMode_t mode)
{
switch (mode)
{
case PM_MEAS_MODE_OPTICAL_ROTATION:
return "Optical rotation";
case PM_MEAS_MODE_SPECIFIC_ROTATION:
return "Specific rotation";
case PM_MEAS_MODE_CONCENTRATION:
return "Concentration";
case PM_MEAS_MODE_SUGAR_SCALE:
return "International sugar scale";
default:
return "Unknown mode";
}
}
/**
* @brief Print measurement results
*
* @param params Pointer to measurement parameters
* @param result Calculation result
*/
void pm_print_measurement_result(pm_params_t *params, float result)
{
ET_INFO("=== Polarimeter Measurement Result ===\n");
ET_INFO("Mode: %s\n", pm_get_mode_name(params->config.mode));
ET_INFO("Zero point: %.4f °\n", params->measured.zero_point);
ET_INFO("Measured value: %.4f °\n", params->measured.measured_value);
ET_INFO("Actual rotation: %.4f °\n", pm_calculate_actual_rotation(params));
ET_INFO("Tube length: %.1f dm\n", params->config.tube_length);
ET_INFO("Temperature: %.1f °C\n", params->measured.temperature);
ET_INFO("Wavelength: %.0f nm\n", params->config.wavelength);
if (!isnan(result))
{
switch (params->config.mode)
{
case PM_MEAS_MODE_OPTICAL_ROTATION:
ET_INFO("Result: %.4f °\n", result);
break;
case PM_MEAS_MODE_SPECIFIC_ROTATION:
ET_INFO("Concentration: %.2f g/100ml\n", params->measured.concentration);
ET_INFO("Result: [α] = %.4f °\n", result);
break;
case PM_MEAS_MODE_CONCENTRATION:
ET_INFO("Specific rotation: %.2f °\n", params->measured.specific_rotation);
ET_INFO("Result: %.4f g/100ml\n", result);
break;
case PM_MEAS_MODE_SUGAR_SCALE:
ET_INFO("Result: %.4f °Z\n", result);
break;
}
}
else
{
ET_ERR("Calculation failed!\n");
}
ET_INFO("===========================\n\n");
}
void pm_params_recompute(pm_params_t *params)
{
if (params == NULL)
return;
params->computed.actual_rotation = pm_calculate_actual_rotation(params);
/* Compute specific rotation if concentration provided */
if (params->measured.concentration != 0.0f)
{
params->computed.specific_rotation = pm_calculate_specific_rotation(params);
}
else
{
params->computed.specific_rotation = params->measured.specific_rotation;
}
/* Compute concentration if specific rotation provided */
if (params->measured.specific_rotation != 0.0f)
{
params->computed.concentration = pm_calculate_concentration(params);
}
else
{
params->computed.concentration = params->measured.concentration;
}
params->computed.sugar_scale = pm_calculate_sugar_scale(params);
}
void pm_params_reset(pm_params_t *params)
{
if (params == NULL)
return;
/* measured */
params->measured.zero_point = 0.0f;
params->measured.measured_value = 0.0f;
params->measured.concentration = 10.0f; /* default 10 g/100ml */
params->measured.specific_rotation = 66.5f; /* default for sucrose */
params->measured.temperature = PM_TEMP_DEF; /* default 20°C */
pm_params_recompute(params);
}
pm_params_t *pm_params_get_instance(void)
{
return pm_params;
}
void pm_params_init(pm_params_t *params)
{
if (params == NULL)
return;
pm_params = params;
/* measured */
params->measured.zero_point = 0.0f;
params->measured.measured_value = 0.0f;
params->measured.concentration = 0.0f;
params->measured.specific_rotation = 0.0f;
params->measured.temperature = PM_TEMP_DEF;
/* config */
params->config.tube_length = PM_TUBE_LENGTH_DEF; /* default 1 dm */
params->config.wavelength = PM_WAVE_LENGTH_DEF; /* sodium D */
params->config.mode = PM_MEAS_MODE_DEF;
pm_params_recompute(params);
}