polarimeter_software/User/app/pm_params.c
2025-09-30 10:37:23 +08:00

257 lines
7.1 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @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);
}