diff --git a/iturhfprop-service/server.js b/iturhfprop-service/server.js index a0c7cf1..35e1aae 100644 --- a/iturhfprop-service/server.js +++ b/iturhfprop-service/server.js @@ -128,45 +128,73 @@ function parseOutputFile(outputPath) { const results = { frequencies: [], - raw: output + raw: output.substring(0, 3000) // Include raw for debugging }; + let headers = []; let inDataSection = false; for (const line of lines) { - // Look for frequency results - // Format varies but typically: Freq, MUF, E-layer MUF, reliability, SNR, etc. - if (line.includes('Freq') && line.includes('MUF')) { + const trimmed = line.trim(); + if (!trimmed || trimmed.startsWith('-') || trimmed.startsWith('*')) { + continue; + } + + // Look for CSV header line + if (trimmed.includes('Freq') || trimmed.includes('FREQ') || trimmed.includes('frequency')) { + headers = trimmed.split(/[,\t]+/).map(h => h.trim().toLowerCase()); inDataSection = true; + console.log('[Parse] Found headers:', headers); continue; } - if (inDataSection && line.trim()) { - const parts = line.trim().split(/\s+/); - if (parts.length >= 4 && !isNaN(parseFloat(parts[0]))) { - results.frequencies.push({ - freq: parseFloat(parts[0]), - muf: parseFloat(parts[1]) || null, - reliability: parseFloat(parts[2]) || 0, - snr: parseFloat(parts[3]) || null, - sdbw: parseFloat(parts[4]) || null - }); + // Parse data lines (CSV or space-separated) + if (inDataSection) { + let parts; + if (trimmed.includes(',')) { + parts = trimmed.split(',').map(p => p.trim()); + } else { + parts = trimmed.split(/\s+/); + } + + if (parts.length >= 2 && !isNaN(parseFloat(parts[0]))) { + const freqResult = { + freq: parseFloat(parts[0]) + }; + + // Map based on headers or position + if (headers.length > 0) { + headers.forEach((h, i) => { + if (i < parts.length) { + const val = parseFloat(parts[i]); + if (!isNaN(val)) { + if (h.includes('snr')) freqResult.snr = val; + else if (h.includes('bcr') || h.includes('rel')) freqResult.reliability = val; + else if (h.includes('pr') || h.includes('power')) freqResult.sdbw = val; + else if (h.includes('muf')) freqResult.muf = val; + } + } + }); + } else { + // Fallback positional parsing + if (parts.length >= 2) freqResult.reliability = parseFloat(parts[1]) || 0; + if (parts.length >= 3) freqResult.snr = parseFloat(parts[2]) || null; + if (parts.length >= 4) freqResult.sdbw = parseFloat(parts[3]) || null; + } + + console.log('[Parse] Frequency result:', freqResult); + results.frequencies.push(freqResult); } } } - // Extract MUF from output - const mufMatch = output.match(/MUF\s*[=:]\s*([\d.]+)/i); + // Also look for MUF in header section + const mufMatch = output.match(/(?:BMUF|MUF|Operational MUF)\s*[:=]?\s*([\d.]+)/i); if (mufMatch) { results.muf = parseFloat(mufMatch[1]); } - // Extract E-layer MUF - const emufMatch = output.match(/E[-\s]*MUF\s*[=:]\s*([\d.]+)/i); - if (emufMatch) { - results.eMuf = parseFloat(emufMatch[1]); - } - + console.log(`[Parse] Found ${results.frequencies.length} frequency results`); return results; } catch (err) { console.error('[Parse Error]', err.message); @@ -235,6 +263,12 @@ async function runPrediction(params) { const elapsed = Date.now() - startTime; console.log(`[ITURHFProp] Completed in ${elapsed}ms`); + // Log raw output for debugging + if (fs.existsSync(outputPath)) { + const rawOutput = fs.readFileSync(outputPath, 'utf8'); + console.log(`[ITURHFProp] Raw output (first 2000 chars):\n${rawOutput.substring(0, 2000)}`); + } + // Parse output const results = parseOutputFile(outputPath); results.elapsed = elapsed; @@ -612,6 +646,11 @@ app.get('/api/bands', async (req, res) => { model: 'ITU-R P.533-14', muf: results.muf, bands, + debug: { + rawOutput: results.raw, + freqCount: results.frequencies.length, + parsedFreqs: results.frequencies + }, timestamp: new Date().toISOString() });