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