Pulscar study: car noise complaints and warning lights (NHTSA ODI complaints) Data pulled 13 September 2026 from https://static.nhtsa.gov/odi/ffdd/cmpl/ Files: COMPLAINTS_RECEIVED_2015-2019.zip, COMPLAINTS_RECEIVED_2020-2024.zip, COMPLAINTS_RECEIVED_2025-2026.zip Unit: one complaint = one ODINO (NHTSA reference number), PROD_TYPE = V, field CDESCR (free text). Received dates (LDATE): 2015-01-01 to 2026-09-08. Unique vehicle complaints: 777,040. 1. SOUND WORDS (Python re, case-insensitive), applied after removing IDIOM matches: W = {'knock':r"\bknock(s|ing|ed)?\b",'tick':r"\bticking\b",'whine':r"\bwhin(e|es|ing)\b",'grind':r"\bgrind(s|ing)\b", 'clunk':r"\bclunk(s|ing|ed)?\b",'rattle':r"\brattl(e|es|ing)\b",'squeal':r"\bsqueal(s|ing)?\b",'squeak':r"\bsqueak(s|ing|y)?\b", 'click':r"\bclick(s|ing)\b",'hum':r"\bhumming\b",'growl':r"\bgrowl(s|ing)?\b",'whistle':r"\bwhistl(e|es|ing)\b", 'roar':r"\broar(s|ing)?\b",'screech':r"\bscreech(es|ing)?\b",'thump':r"\bthump(s|ing)?\b",'bang':r"\bbang(s|ing)?\b", 'pop':r"\bpop(s|ping)\b",'noise':r"\bnois(e|es|y)\b"} 2. IDIOMS removed before matching (not a mechanical sound): IDIOM = re.compile(r"clicks? off|clicking off|screeching (halt|stop)|bells and whistles|knock(s|ed|ing)? (\w+ ){0,3}(unconscious|out|over|down|off|loose)\b|knock(s|ed|ing)? (me|him|her|them|us|it)\b|pop(s|ped|ping)? (up|on|open|out)\b|\bno (funny |strange |weird |unusual |abnormal |odd |loud )?(noises?|sounds?)\b|noises? of the (alert|alarm|chime|warning)|(alert|alarm|chime|beep)\w* noise|warning noise",re.I) 3. CLASSIFICATION of each sound complaint, checked in this order: explicitly_no_warning if NEG matches warning_mentioned else if POS matches no_warning_mentioned otherwise NEG = re.compile(r"\b(no|never|not any|zero)\s+(dash(board)?\s+|check engine\s+|warning\s+|engine\s+|error\s+|trouble\s+)*(warning\s+)?(lights?|lamps?|codes?|indicators?|messages?|alerts?|warnings? (lights?|on the dash|came|appeared|displayed|showed|illuminated))\b(?! (at|on) (the )?(street|intersection|corner|road))|\b(warning|check engine|dash(board)?) lights? (did not|didn'?t|never|failed to|would not|wouldn'?t) (come|came|illuminate|turn|go|light|appear|show)|\bwithout (any )?(warning )?(lights?|codes?|indicators?|messages?)\b|\bno (warnings?|alerts?|messages?) (on|in|from) the (dash|dashboard|instrument|cluster|display|screen|car|vehicle|truck)",re.I) POS = re.compile(r"\b(warnings?|check engine|service engine|engine light|(abs|tpms|oil|battery|brake|traction|airbag|air bag|temperature|temp|stability|esc|epb|coolant) (light|lamp|warning|message)s?|lights? (came|come|comes|went|turned|flash\w*|illuminat\w*)|illuminat\w*|dash(board)? (lights?|messages?|alerts?|warnings?)|messages?|indicators?|lamps?|dtcs?|codes?|limp mode|reduced (engine )?power|chimes?|alerts?|beep\w*)\b",re.I) 4. HAND AUDIT: 40 random sound matches read in full on the final rules: 39 describe a sound; warning classification wrong in 2 of 40 (one in each direction). Earlier audits of 25 explicit matches: 25 of 25 were genuine statements that no light, code or message appeared. 5. "pct_not_reporting_warning" = (no_warning_mentioned + explicitly_no_warning) / complaints. 6. A complaint can carry several component systems (COMPDESC); by_system counts it once per system. 7. Complaints are self-reported and unverified. Absence of a mention is not proof no light came on. License: CC BY 4.0, credit "Pulscar analysis of NHTSA complaint data" with a link to the study page. 8. ADDED 13 September 2026 (second release) vehicle age = year received (LDATE) minus model year (YEARTXT), model years 1990-2027 only. powertrain class from MODELTXT/MAKETXT names only (heuristic; FUEL_TYPE is blank in 95% of sound complaints): ELECTRIC = \b(EV\d?|ELECTRIC|LIGHTNING|BOLT|LEAF|MODEL [3SXY]|MACH-E|IONIQ 5|IONIQ 6|EV6|EV9|ID\.4|I3|TAYCAN|R1T|R1S|LYRIQ|HUMMER EV|SOLTERRA|BZ4X|ARIYA|NIRO EV|KONA ELECTRIC|POLESTAR)\b or make TESLA/RIVIAN/LUCID/POLESTAR HYBRID = HYBRID|PHEV|PLUG-?IN|PRIUS|HEV\b|4XE ENGINE_FAILURE_DESCRIBED = engine (failure|failed|seized|seize|locked up|blew|blown|replace(d|ment)?|needs? (to be )?replaced)|seized|new engine|replace the engine|rod bearing|spun (a )?bearing|thrown rod STALL_OR_LOSS_OF_POWER = \bstall(ed|s|ing)?\b|los(s|t|e|ing) (of )?(motive |all )?power|lost power|shut (off|down)|died while driving SHOP_COULD_NOT_FIND = (could ?n[o']?t|can ?n[o']?t|could not|cannot|unable to|were not able to|was not able to|failed to|did not|didn'?t) (duplicate|replicate|reproduce|find (anything|any problem|the problem|a problem|the issue|an issue|the cause|the source)|locate (the )?(problem|issue|noise|source)|hear (the|any|it)|verify)|no (problem|trouble|issue|fault)s? (was |were )?found|nothing (was )?(found|wrong)|could not be (duplicated|replicated|reproduced|determined|found)|cause (of the failure )?(could not|was not) (be )?(determined|found)|failure could not be (duplicated|determined)|operating as designed|normal (operation|characteristic)|is normal Hand audits: 15 random engine-failure matches in the explicit group, 15 described a failed, seized or replaced engine; 15 random shop-could-not-find matches, 15 described a shop that found nothing, could not duplicate, or called it normal.